Aglets Specification (1.0)
- Version 0.60
- May 20th, 1997
- Author: Mitsuru Oshima
and Guenter Karjoth
-
Send comments to aglets@yamato.ibm.co.jp.
Introduction
Overview
Aglets are Java objects that can move from one host on the network
to another. That is, an aglet that executes on one host can suddenly
halt execution, dispatch to a remote host, and start executing again.
When the aglet moves, it takes along its program code as well as
the states of all the objects it is carrying. A built-in security
mechanism makes it safe to host untrusted aglets.
System Goals
- Provide an easy and comprehensive model for programming mobile agents
without requiring modifications to Java VM or native code.
- Support dynamic and powerful communication that
enables agents to communicate with unknown agents as well as
well-known agents.
- Design a reusable and extensible architecture.
- Design a harmonious architecture with existing Web/Java technology.
Aglet Object Model
Aglet API Overview
The Aglet API defines the fundamental functionality of mobile agents. The
following figure shows the major interfaces and classes defined in
the Aglet API and the relationship between these interfaces.
- com.ibm.aglet.Aglet
- The Aglet abstract class defines the fundamental methods
(for example, dispatch(URL)) for a mobile agent.
to control their mobility and lifecycle.
All mobile agents defined in Aglets have to extends this
abstract class.
The Aglet.dispatch(URL) primitive causes an aglet to move
from the local host to the destination given as the argument.
The Aglet.deactivate(long time) primitive allows an aglet
to be stored in secondary storage, and the Aglet.clone()
primitive spawns a new instance of the aglet which has the state of
the original aglet. Note that the object returned by the
clone primitive is not an Aglet object but an AgletProxy
object.
The Aglet class is also used to access the attributes associated
with an aglet. The com.ibm.aglet.AgletInfo object, which
can be obtained by Aglet.getAgletInfo(), contains
an aglet's inherent attributes, such as its creation time and
codebase, as well as its dynamic attributes, such as its arrival
time and the address of its current context.
- com.ibm.aglet.AgletProxy
- The AgletProxy interface acts as a handle of an aglet and
provides a common way of accessing the aglet behind it.
Since an aglet class has several public methods that
should not be accessed directly from other aglets for
security reasons, any aglet that wants
to communicate with other aglets has to first obtain the proxy object,
and then interact through this interface. In other words,
the aglet proxy acts as a shield object that protects an agent from
malicious agents. When invoked, the proxy object consults the
SecurityManager to determine whether the current execution context
is permitted to perform the method. Another important role of the
AgletProxy interface is to provide the aglet with location
transparency.
If the actual aglet resides at a remote host, it forwards
the requests to the remote host and and returns the result to
the local host.
The AgletProxy can be obtained in the following ways:
- Get an enumeration of proxies in a context by calling the
primitive AgletContext.getAgletProxies().
- Get an AgletProxy for a given AgletID via either
AgletContext.getAgletProxy(AgletID) or
Aglets.getAgletProxy(String contextName, AgletID).
- Get an AgletProxy object by message passing. An AgletProxy object
can be put into the Message object as an argument, and sent to the
aglet locally or remotely.
- Put an AgletProxy object into the ContextProperty by
AgletContext.setProperty(String,Object),
and share the proxy object.
The runtime library is responsible for providing the implementation
of the AgletProxy interface; thus, aglet programmers do
not have to implement this interface.
- com.ibm.aglet.AgletContext
- AgletContext provides an interface to the runtime
environment that occupies the aglet.
Any aglet can obtain a reference to its AgletContext object
via the Aglet.getAgletContext() primitive, and use it to
obtain local information such as the address of the hosting context
and the enumeration of AgletProxies, or to create a new aglet in the
context. Once the aglet has been dispatched, the context object
currently occupied is detached and the new context is attached.
The runtime library is responsible for providing the implementation
of this interface; thus, aglet programmers do hot have to implement
this interface.
- com.ibm.aglet.Message
- Aglet objects communicate by exchanging objects of the
Message class. A message object can have a String object
to specify the kind of the message and arbitrary objects as arguments.
A message can be sent to the aglet by calling
Object AgletProxy.sendMessage(Message msg) ,
FutureReply AgletProxy.sendAsyncMessage(Message msg)
, or
void AgletProxy.sendOnewayMessage(Message msg)
and it is passed as an argument to
Aglet.handleMessage(Message msg).
Please see the section on messaging for more
details.
- com.ibm.aglet.FutureReply
- The object defined by the FutureReply interface is returned
by the asynchronous message-sending and used as a handler to receive
the result later asynchronously. With this interface, the receiver
can determine whether a reply is available, and can wait for the
result with a specified timeout value so that it can continue its
execution if a reply was not returned within the specified time.
In the following sections,
you will see more classes and interfaces
that allow you to control the activities of an aglet.
Extending the Aglet class
Here are the general rules for extending an abstract Aglet
class.
- A user-defined Aglet class extends the com.ibm.aglet.Aglet class.
- It can extend another Aglet implementation class.
- It can implement a java.io.Externalizable interface.
- It cannot override pre-defined Aglet API methods, such as
dispatch() and getAgletContext() since
these are declared to be final.
- The aglet class should not implement a constructor with 0 arguments.
However, you may have to implement an empty constructor if the aglet
implements java.io.Externalizable.
ObjectSerialization invokes the constructor of the object that
implements an Externalizable interface, and fails
if no public constructor exists. Please note that it must be
empty, because the constructor is called even during
deserialization of objects. This leads to the object being
initialized every time it is dispatched or deactivated.
This doesn't happen unless the aglet implements
java.io.Externalizable.
The following methods of the Aglet class are supposed to be
overridden by a subclass to allow an aglet to implement its
own specific behavior:
- void Aglet.onCreation(Object init)
- This method is supposed to be called only once during its
lifecycle, when it is created. Aglet programmers have to use
onCreation(Object init) to initialize an aglet object,
because the Aglet API (dispatch(URL) for example) is
not available in the constructor.
- void Aglet.onDisposing()
- This method is called when an aglet is disposed of.
The aglet is supposed to release any resources previously
allocated. It can perform additional actions in response to
its own disposal.
- void Aglet.run()
- The run() method in the Aglet class is called whenever an
instance is reconstructed, that is, when the instance is created
when it is cloned, when it arrives at the destination, and
when it is activated.
Because this method is called whenever it occupies the context,
this is a good place to define the common task.
- boolean Aglet.handleMessage(Message msg);
- All messages sent to the aglet are passed to the
handleMessage method. Aglet programmers can check
whether the incoming message is a known message, and can perform
the task according to the kind of message.
public class HelloAglet extends Aglet {
public void onCreation(Object init) {
System.out.println("created!");
}
public void run() {
System.out.println("hello!");
}
public boolean handleMessage(Message msg) {
if (msg.sameKind("sayHelloAgain") {
System.out.println("hello!");
return true;
}
return false;
}
public void onDisposing() {
System.out.println("bye!");
}
}
Aglet Object and Its Life Cycle
The Aglets class provides the basic functionality for a mobile object, and
every mobile object (aglet objects) has to be an instance of a subclass of
the com.ibm.aglet.Aglet class. To be useful, an aglet has to be
instantiated first. There are two ways to create a new instance of an
aglet. The first is to instantiate a completely new aglet from class
definitions by calling
AgletContext.createAglet(URL codebase, String name, Object init).
This primitive creates a new instance within the specified context and
initializes it if necessary, then invokes
Aglet.onCreation(Object init)
on the created object along with the initializer object passed to the
createAglet primitive.
The other way is to create a copy of an existing aglet by using
the Aglet.clone() primitive. The cloned aglet has the same
state as the original one but has a different AgletID object, an thus
a distinct identity.
Once created, an aglet object can be dispatched to and/or retracted
from a remote host, deactivated and placed in secondary storage,
then activated later.
An aglet can dispatch itself to a remote host by calling the
Aglet.dispatch(URL dest) primitive. To be
more precise, an aglet occupies the aglet context and
can move from this context to others during its execution.
Because the runtime system may serve multiple contexts within
one Java VM, these contexts can be in the same VM. Dispatching
causes an aglet to suspend its execution, serialize its
internal state and bytecode into the standard form and then
to be transported to the destination. On the receiver side,
the Java object is reconstructed according to the data
received from the origin, and a new thread is assigned and
executed.
Aglets support persistency of aglet objects. All mobile aglet objects can
be persistent in nature, because they must be convertable into
a bit-stream; consequently, this stream can be stored in secondary storage.
The Aglet.deactivate(long timeout) primitive causes an aglet
to be stored in secondary storage and to sleep for a specified number of
milliseconds. After the given time has passed or another program has
requested its activation,
the aglet is activated within the same context where as that in which
it was deactivated.
Unlike normal Java objects, which are automatically released by
garbage collector,
an aglet object, since it is active, can decide whether or not to die.
If you call the dispose() method to kill the
aglet, onDisposing() is called to perform
the finalization suitable for the current state of the aglet.
Aglet programmers are responsible for releasing allocated
resources such as file descriptors or DB connections, because these may
not be released automatically.
Once disposed of, the instance becomes an invalid entity, and any attempt
to operate it will result in a SecurityException.
(This may be replaced with another Exception class).
Aglets Event and Delegation Event Model
Java VM doesn't allow to marshal the stack frame of a Thread object.
It is impossible to migrate a Thread object to a remote host or
to save it to secondary storage while preserving its execution state.
Instead, Aglets uses an event model to give programmers
a chance to implement an action that emulates the migration.
When an aglet dispatches, the
Aglet runtime system issues the corresponding event to notify that
it is being dispatched, or it is arriving at the destination.
For example, the following code fragment defines the
MyListener class, which implements the MobilityListener
interface, and MyAglet, which extends the Aglet class.
import com.ibm.aglet.Aglet;
import com.ibm.aglet.event.MobilityEvent;
import com.ibm.aglet.event.MobilityListener;
class MyListener implements MobilityListener {
public void onDispatching(MobilityEvent l) {
}
public void onReverting(MobilityEvent l) {
}
public void onArrival(MobilityEvent l) {
}
}
public class MyAglet extends Aglet {
public void onCreation(Object init) {
MobilityListener listener = new MyListener();
addMobilityListener(listener);
}
}
Before an aglet is actually dispatched, the onDispatching() method of the
MyListener object is called,
and the onArrival() method is called after the aglet arrives at its
destination.
In this way, an aglet programmer can implement an action that
should be taken in response to these events (dispatch, for instance)
regardless of when or by whom an aglet is dispatched.
When | Event Object | Listener | Method called |
about to be cloned | CloneEvent | CloneListener | onCloning |
clone is created | CloneEvent | CloneListener | onClone |
after the clone was created | CloneEvent | CloneListener | onCloned |
about to be dispatched | MobilityEvent | MobilityListener | onDispatching |
about to be retracted | MobilityEvent | MobilityListener | onReverting |
after arrived at the destination |
MobilityEvent | MobilityListener onArrival |
|
about to be deactivated | PersistencyEvent | PersistencyListener | onDeactivating |
after activated | PersistencyEvent | PersistencyListener | onActivation |
Note that these callbacks are also inserted into the message queue.
You will not receive the event until the current message owning
the monitor is completed.
Please refer to the messaging section for more
details.
Difference between writeObject/readObject Methods and Listeners
ObjectSerialization provides an object with a way of customizing
its own serialization by overriding two method, called
writeObject(ObjectOutputStream) and
readObject(ObjectInputStream).
These can be used to implement an action
that should be taken in response to an AgletEvent, because
these two methods are always called when such an event occurs.
The AgletEvent callbacks are different from the readObject/writeObject
method in the sense that the aglet programmer can determine what
kind of event occurred and can thus implement a different behavior for
each event. For example, different behaviors are often implemented for
the original object and its clone object, depending on whether
the object is a parent or a child. The following code fragments
define the CloneLimiter, which controls the maximum number of
clones the aglet can create.
public class CloneLimiter implements CloneListener() {
boolean original = true;
int number_of_clones = 0;
public void onCloning(CloneEvent ev) {
if (original == false) {
throw new SecurityException("Clone cannot create a clone");
// this exception may be replaced with another class.
}
if (number_of_clones>10) {
throw new SecurityException("Exceeds the limit");
}
}
public void onClone(CloneEvent ev) {
original = false;
}
public void onCloned(CloneEvent ev) {
number_of_clone++;
}
}
Unlike overriding the readObject/writeObject methods, listener
objects are pluggable and can be added to and removed from the aglet at
runtime, so listener classes can be used as a library for aglets.
You can use the CloneLimiter class for any aglet class to
specify the maximum number of clones, for example.
Another important difference the aglet programmer should
be aware of is that onDispatching() is called while the aglet is
running, while the writeObject is called after the aglet is suspended.
Similarly, readObject() is called while being unmarshaled,
which means that Aglet primitives such as getAgletContext() do not work.
On the other hand, onArrival() is called after the entire aglet has
been restored and activated successfully, so you can call the Aglets API.
However, readObject/writeObject is the right place to implement
general and common behavior for storing or restoring the state of
an object.
Migration of Object in Aglets
Serializing an Aglet Object
When and aglet is dispatched, cloned or deactivated, it is marshaled into
a bit-stream, then unmarshaled later.
Aglets uses ObjectSerialization of Java to marshal and unmarshal the
state of agents, and tries to marshal all the objects that are reachable
from the aglet object. All objects to be serialized have to
implement either java.io.Serializable or
java.io.Externalizable.
If there is a non-serializable object that is directly or indirectly
referenced by an aglet, you should declare the reference as
transient. Otherwise, the above operations will
fail and will throw a java.io.NotSerializableException that
is a subclass of the java.io.IOException class.
Serializing Nonproxy Objects
A nonproxy object, which is reachable from an aglet, is migrated by
copy. This means that once serialized, an object shared
by multiple aglets is copied and is no longer shared
after the above operations.
Serializing Proxy Objects
When a proxy object is migrated, it keeps the aglet id and its address,
and restores the reference to the original aglet object.
The AgletProxy object can keep the reference to
the actual aglet even if the proxy is transferred to a remote host or
deactivated, as long as the aglet resides in the same location.
Remote Objects in RMI
The remote interface is defined in RMI and is used to identify
remote objects whose methods can be invoked remotely.
The RMI Client program works with the Aglets library without
modification. That is, when dispatching an aglet along with the remote
object, it is automatically rebound when the aglet is unmarshaled.
RemoteServer Objects in RMI
RemoteServer objects defined by RMI are stationary objects, thus
it cannot be transferred along with your aglet. This support will
be supported in the future.
Proxy Object Whose Aglet is Dispatched
Currently, the AgletProxy cannot keep track of roaming aglets. Once an
aglet is dispatched, the proxy previously referencing the aglet is
no longer valid. A mechanism for preserving the reference will be
provided in the future.
How Dispatch Works
When an aglet is dispatched, corresponding listener objects are called
immediately.
If these invocations are successfully completed, a thread
is suspended first, then ObjectSerialization is called and
the aglet and its associated objects are marshaled. After these
objects have been successfully marshaled and transported to the
destination, the thread is killed and related resources are
deallocated.
If the aglet has more than one thread created by itself,
these threads are also automatically terminated. To avoid any problem
caused by unexpected termination, an aglet should implement a listener
interface and terminate these threads in the listener's callback method.
Messaging in Aglets
An application program or an aglet can communicate with
the aglet object by message passing. An aglet that wants to
talk to another aglet first has to create a message object, then
send it to the peer aglet. A message object has, as its argument,
a kind attribute of the class message and an arbitrary object.
The receiver aglet can determine what to do by checking the kind of
received message in the Aglet.handleMessage() method.
MyAglet extends Aglet {
public boolean handleMessage(Message msg) {
if (msg.sameKind("doJob")) {
doJob();
} else if (msg.sameKind("shutdown")) {
deactivate(0);
}
}
}
Aglets supports the following types of message passing:
- Now-type:
AgletProxy.sendMessage(Message msg)
- A now-type message is synchronous and blocks until the receiver
has completed the handling of the message.
String answer = proxy.sendMessage(new Message("question"));
System.out.println(answer);
- Future-type:
AgletProxy.sendAsyncMessage(Message msg)
- A future-type message is asynchronous and does not block the current
execution. The method returns an FutureReply object, which
can be used to obtain the result or wait for it later.
FutureReply future =
proxy.sendAsyncMessage(new Message("question"));
int num_task = 10;
// do private job at most 10 times while waiting for the result.
while(future.isAvailable() == false && num_task-- >0) {
doPrivateJob();
}
System.out.println( (String)future.getReply() );
Note: If an aglet sends a message to itself,
the message is not put at the tail of the queue. Instead, it is placed
at the head of the queue and executed immediately, to avoid deadlock.
- Oneway-type:
AgletProxy.sendOnewayMessage(Message msg)
- A oneway-type message is asynchronous and does not block the current
execution.
It differs from a future-type message
in the way it is placed at the tail of the queue even if it is sent
to the aglet itself.
[, does not have return value.]
proxy.sendOnewayMessage(new Message("question"));
Note: Oneway type message passing is not
implemented as of this writing.
The receiver aglet has to define its
handleMessage(Message msg) method
to handle the incoming messages. In the handleMessage method,
a message object is passed as an argument and can be used to perform
the operation according to the kind of message. If it is handled,
the method has to return a boolean value indicating whether
it has been handled or not.
public boolean handleMessage(Message msg) {
if (msg.sameKind("sayHello")) {
System.out.println("Hello");
return true; // i know this message...
}
return false; // false, otherwise
}
If it returns false, the sender of the message receives a
NotHandledException and thus knows that the message has not been handled.
There is no way of knowing whether a oneway message has been handled or
not.
Future future = proxy.sendAsyncMessage();
...
try {
Object reply future.getReply();
} catch (NotHandledException ex) {
// the receiver didn't handled the message
} catch (MessageException ex) {
// an exception has been throwen in the receiver's handleMessage()
System.out.println(ex.getException());
}
Messages in Aglets also support acknowledge-type replies, whereby
the receiver can send the reply (result) even before completing
the handling of the message. When you have a return value, you need
to use this interface to return the value.
Once you send a reply via the Message.sendReply() method,
you cannot send a reply again, and the return value of
handleMessage will be ignored.
public boolean handleMessage(Message msg) {
if (msg.sameKind("accessDB")) {
openDB(); // pseudo code
Object reply = accessDB(msg.getArg());
msg.sendReply(reply);
closeDB();
return true; // i know this message...
}
return false; // false, otherwise
}
Message Queue and Priority
All aglet objects have a message queue object. All incoming messages are
stored in the message queue, basically, and then handled one by one.
The messaging in Aglets follows the transmission-ordering law;
that is, messages arrive in the order in which they were sent. For example,
if you send messages in the order "A", "B", "C", the receiver receives
them in the same order "A", "B", "C".
queue
[A] -> {}: Aglet
[B] -> {[A]}: Aglet
[C] -> {[B][A]}: Aglet
{[C][B]}: Aglet ( handling [A] )
{[C]}: Aglet ( handling [B] )
{}: Aglet ( handling [C] )
You can specify the priority associated with kinds of messages.
The messages with high priority are queued in higher positions.
Suppose that there are three messages in the queue, with the priorities
3, 5, and 6, and that you send two messages with priorities 4 and 7
asynchronously. Even if you sent the message with priority 4
first, the message with priority 7 will be handled first.
{[3][5][6]}: Aglet
[4] -> {[3][5][6]}: Aglet
[7] -> {[3][4][5]}: Aglet (handling [6])
{[3][4][5][7]}: Aglet (handling [6] cont'd)
{[3][4][5]}: Aglet (handling [7])
Aglets also supports a NOT_QUEUED priority, whereby the message
is not queued. Suppose the Message [D] has priority NOT_QUEUED;
then that message will be passed to an aglet and handled immediately.
[A] -> {}: Aglet
[B] -> {[A]}: Aglet
[D] -> {[B][A]}: Aglet
{[B]}: Aglet ( handling [A] ) ( handling [D] )
{}: Aglet ( handling [B] ) ( handling [D] )
{}: Aglet ( handling [D] )
You can set priority of the message by the primitive
MessageManager.setPriority(String, int), and
a MessageManager object of the agent can be obtained via
Aglet.getMessageManager() primitive.
Synchronizing Messages
Although messages are normally handled one by one, it
often happens that the thread currently handling the message
has to wait until the aglet's state meets some condition, or has to inform
the waiting thread or incoming message that the condition is satisfied.
The Aglet API has five methods to synchronize messages.
- Aglet.waitMessage();
Aglet.waitMessage(long timeout);
- Aglet.waitMessage() causes the current thread to wait
until another message instructs it to resume
its execution.
Only the thread that owns the message-handling monitor can call
this method and wait. Otherwise, the IllegalMonitorStateException
will be thrown.
If another thread handling another message instructs the waiting
thread to resume the waiting thread by calling
Aglet.notifyMessage(), it wakes up and resumes
execution. If it is not instructed to resume, it will wait forever
until it is stopped. On the other hand, the
waitMessage(long timeout) is used to wait at most
for timeout millisecond, and wakes up
when the specified timeout expires.
- Aglet.notifyMessage();
Aglet.notifyAllMessages();
-
Aglet.notifyMessage() instructs the waiting thread to
wake up and resume execution. The caller thread is put
at the head of the message queue and waits until the resumed thread
completes the message handling or exits the monitor.
Only the thread that owns the message-handling monitor can
call this method. Otherwise the IllegalMonitorStateException will
be thrown.
queue waiting
{[D][C]}: Aglet {[A][B]}
{[D]}: Aglet {[A][B]} (handling[C] calls notifyMessage())
{[D][C]}: Aglet {[B]} (handling[A])
Aglet.notifyAllMessages() causes
all waiting threads to wake up one by one. These threads
are placed at the head of the message queue and the oldest
waiting thread is immediately resumed. The caller thread
is placed at the next position of these thread and
will be resumed alter these resumed thread has completed.
queue waiting
{[D][C]}: Aglet {[A][B]}
{[D]}: Aglet {[A][B]} (handling[C] calls notifyAllMessages())
{[D][C][B]}: Aglet (handling[A])
- Aglet.exitMonitor();
- exitMonitor() causes the current execution thread
to release the monitor owned by the thread and exit the
synchronization block. The next message in the message queue
is then executed. Note that exitMonitor()
does not activate the waiting messages but only the
incoming messages.
queue
{[C][B]}: Aglet (handling[A]* calls exitMonitor())
{[C]}: Aglet (handling[B]*) (handling[A])
Note: * indicates the owner of the monitor
With this API, you can implement a background task while receiving
the message.
public void SiteWatcherAglet extends Aglet {
public void run() {
exitMonitor(); // now the next message would start.
while( condition == true) {
watchSite("http://home/index.html");
}
}
}
The following "StackAglet" example illustrates how synchronization between
messages can be achieved.
public StackAglet extends Aglets {
static int capacity = 10;
Object stack[] = new Object[capacity];
int num = 0;
public handleMessage(Message msg) {
if (msg.sameKind("push")) {
push(msg);
} else if (msg.sameKind("pop")) {
pop(msg);
} else if (msg.sameKind("isFull")) {
msg.sendReply( num == capacity);
} else if (msg.sameKind("isEmpty")) {
msg.sendReply( num == 0 );
} else return false;
return true;
}
private void push(Message msg) {
while (num == capacity) {
waitMessage();
}
stack[num++] = msg.getArg();
if (num==1) {
notifyMessage(); // wake up "pop" message
}
}
private void pop(Message msg) {
while(num==0) {
waitMessage();
}
msg.sendReply(stack[--num]);
if (num == (capacity -1)) {
notifyMessage(); // wake up "push" message
}
}
}
Note:
Remote Messaging in Aglets
Aglets supports remote message passing, and aglet objects can
communicate through messages remotely as well as locally. Parameter
objects or return value passed by remote messaging can be of any
Java type that implements java.io.Serializable, and are
marshaled and unmarshaled by ObjectSerialization. Sending
a remote message is different from dispatching an aglet
in a sense that a remote message does not cause any transfer of
bytecode, and therefore the classes used in the message have to be
installed in both hosts.
Remote message passing can be used as a lightweight way of
communicating between aglets that reside on the different hosts,
and can reduce the network traffic, the cost of defining
classes, and security issues, while dispatching an aglet can
take advantage of locality, for example disconnected operations or
intensive interaction with hosts.
Exception Handling in Aglets
T.B.D.
System Architecture
Overview
The Aglets architecture consists of two APIs and two implementation layers.
- Aglet API
- Aglets Runtime Layer - The implementation of Aglet API
- Agent Transport and Communication Interface
- Transport Layer
The Aglets runtime layer is the implementation of Aglet API, which
provides the fundamental functionality such as creation, management or
transfer of aglets. This layer defines the behavior of APIs such as
Aglet and AgletContext, and can serve multiple AgletContext objects.
The transport layer is responsible for transporting an agent to the
destination in the form of a byte stream that contains class definitions
as well as the serialized state of the agent.
This layer is also defined as an API, called Agent Transfer and
Communication Interface (ATCI), which allows the Aglets runtime to use
the transport layer in a protocol-independent manner.
The implementation of ATCI is responsible for sending and receiving an
agent and establishing a communication between agents.
The current Aglets implementation uses the Agent Transfer Protocol (ATP),
which is an application-level protocol for transmission of mobile agents.
ATP is modeled on the HTTP protocol, and can be used to transfer the
content of an agent in an agent-system-independent manner.
To enable communication between agents, ATP also supports
message-passing.
When an aglet issues a request to dispatch itself to a destination,
the request travels down to the Aglets runtime layer,
which converts the aglet into the form of a byte array
consisting of its state data and its code.
If the request is successful, the aglet is terminated, and the byte array
is passed to the ATP layer through the ATCI.
The ATP, which is the implementation of ATCI, then constructs a bit
stream that contains general information such as the agent system name
and agent identifier, as well as the byte array from the Aglets runtime.
Note: The API of the transport Layer, ATCI, will be
replaced with the MAF standard interface currently being proposed to
Object Management Group (OMG).
Agent Transfer Protocol
ATP is a simple application-level protocol designed
to transmit an agent in an agent-system-independent manner. Its request
consists of a request line, header fields, and a content.
The request line specifies the method of the request, while the header
fields contain the parameters of the request. ATP defines the following
four standard request methods:
- Dispatch
- The dispatch method requests a destination agent system to
reconstruct an agent from the content of a request and
start executing the agent. If the request is successful, the sender
must terminate the agent and release any resources consumed by it.
- Retract
- The retract method requests a destination agent system to
send the specified agent back to the sender. The receiver
is responsible for reconstructing and resuming the agent.
If the agnet is successfully transfered, the receiver must
terminate the agent and release any resources consumed by it.
- Fetch
- The fetch method is similar to the GET method in HTTP; it requests
a receiver to retrieve and send any identified information.
(normally class files).
- Message
- The message method is used to pass a message to agent identified by
agent-id and return a reply value in the response.
Although the protocol adopts a request/reply form, it does not lay down
any rules for communication scheme between agents.
Please refer to the
ATP specification
for more details.
Note:
Aglets team is currently working on standardization of the agent transfer
layer, as a part of the Mobile Agent Facility (MAF) standard proposing to
OMG. If it is accepted, we may change the interface of the transport layer
from ATCI to MAF and provide a new transport layer with CORBA/IIOP,
as well as ATP.
Thread Usage in ATP
The ATP implementation does not require creation of a new thread to
handle an incoming connection request. Instead, ATP contains a pool of
threads and pulls out an available thread from it, then assigns it to
handle the request. Consequently, it is possible to handle multiple
requests efficiently. Since an aglet has its own threads of control,
it is guaranteed that all threads used to call it belong to the aglet's
thread group, and are not the same as the threads in the pool.
Proxy and Reference Architecture
T.B.D.
Class Loading and Mobility
In Aglets, a class for creating an aglet is determined dynamically at
runtime; thus, the class definitions(bytecode) for the aglet need
to be loaded dynamically as required. This dynamic class-loading may
occur during the aglet's execution at destination hosts as well as when
the aglet is created.
Furthermore, in mobile agent systems, class definitions
are transmitted along with an aglet's state as it moves.
The following questions are therefore of interest to the aglet developer:
- How a class loader is chosen.
- How a class definition is transmitted.
How a Class Loader is Chosen
In Java, the class loader that first loads a class is used to load
all subsequent interfaces and classes that are used directly in the class.
In Aglets, the AgletClassLoader is used by default to load aglet classes.
A class loader is chosen in accordance with its codebase, which is given
as an argument to
AgletContext.createAglet(URL codebase, String name, Object init)
primitive at the time of creation; thus, a new instance of
AgletClassLoader is created for each codebase, and aglet objects that
have the same codebase share the same class loader as a general rule.
A codebase is an immutable attribute of an aglet, and never changes during
its lifecycle. The following are examples of codebase definitions:
- Directory
- atp://mycomputer.com:434/AWB/Aglets/public
- http://codeserver.com/~userid/aglets
- file:///AWB/Aglets/public
- Jar files
- http://codeserver.com/home/moshima/Aglets/public/helloAglet.jar
If the null value is given as an argument to the primitive,
the Aglets library looks up the class in the directories in the AGLET_PATH
and locates the directory in which the class for the specified name was
found.
If a class is found in the local CLASSPATH, however, the AgletClassLoader
delegates the request to the system class loader and that class loader
is used to load the class. All classes used directly in the class
are subsequently loaded by the system class loader. Note that this occurs
even when the aglet class itself is loaded, and that the aglet therefore
has no class loader. If the aglet class definition is located on the
CLASSPATH, the entire aglet will be loaded by the system class loader.
As a consequence, all classes to be loaded by an aglet have to be
available either in the codebase or on the CLASSPATH. There is no way to
load a class from a place other than the CLASSPATH and the codebase.
When an aglet is dispatched or deactivated, the codebase of the aglet
is stored in the stream and used to create a new class loader for the
aglet. If a class loader with the same codebase already exists
in the cache, it is used as the class loader for the aglet to
define the incoming classes, instead of creating a new one.
All subsequent classes used directly by classes defined by this class
loader are loaded by either the same class loader or the system class
loader.
Class Cache and Bytecode Evolution
The AgletClassLoader has a class cache, and stores all classes that
it is requested by aglets to load from its codebase. If the class
requested by an aglet already exists in the cache, it is used
instead of downloading a new class from the codebase; thus
reduces the network load and improves the performance.
There may be cases, however, in which the bytecode of an aglet has been
updated and the new class definition conflicts with an existing class
cached in the class loader.
When an aglet is dispatched, the Aglets runtime that receives the aglet
checks whether the incoming class definitions are fully compatible with
existing classes in the cache and creates a new loader if there is at
least one conflicting class.
Note that only classes stored in the stream are checked, while
classes to be dynamically loaded later are not checked.
In other words, the current runtime library does not check whether new
classes are located in the codebase when an aglet is created.
This will be improved when Aglets supports "Jar" format.
Class Mobility
In mobile agent systems, class definitions are transmitted along
with their state as the agent moves.
Aglets classifies Java classes into three categories, according to
their codebases, and manages them in different ways.
- A System Class
- A class which is loaded from CLASSPATH; and thus, does not have a
codebase.
- A Codebase Class
- A class that is loaded from the aglet's codebase.
- Other Classes
- An aglet might refer to other classes that are loaded from
other codebases by other aglets. This happens when an aglet
receives a message that includes as an argument
an object whose class was loaded from the sender's codebase.
When an aglet is dispatched or deactivated, the bytecode of codebase
classes used by it are stored in stream form during the process of
ObjectSerialization, and then sent to the destination or placed in
secondary storage. In contrast, the system classes are not stored in the
stream.
Consequently, they never get sent to the destination. In other words,
Aglets assumes that all system classes used by an aglet are available at
the destination as well. If any one of these classes is not available at
the destination,
the dispatch operation will fail with an exception.
On the other hand, if a user attempts to serialize an object whose
class loader is different from the aglet's class loader, it
will fail with a SecurityException. This is because Aglets does not
allow an aglet to load a class from two different codebases, for
security reasons.
When an aglet arrives or is activated, the bytecode in the stream is
retrieved and then used to define the classes needed to reconstruct
the aglet.
If a local class has the same name as a class in
the stream transmitted, the local class is chosen and used to
reconstruct the aglet. If the local class is not compatible
with the original class in terms of the serialization, it will also fail
with an exception.
Security
When bytecode is carried out, the runtime consults the SecurityManager
to determine whether an aglet is allowed to carry it out. When bytecode
is carried in, it does so to determine wheter the aglet is allowed to
carry the bytecode into the runtime and to define the class.
Furthermore, a request from an aglet that went out of the server
to fetch a class file must also be referred to the SecurityManager.
If the requested file is not allowed to be fetched, the SecurityManager
refuses the request.
Resource Management
T.B.D
HTTP Tunneling via Proxy Servers
The ATP layer normally attempts to make a direct connection
to hosts on the network. In almost all intranet situations, however,
there is a firewall that prevents users from opening a direct socket
connection to an external node. This means that an aglet cannot be
dispatched or retracted through the firewall.
To make it possible, the ATP layer supports a technique called
HTTP tunneling that enables an ATP request to be sent outside of
the firewall as a HTTP POST request and the response to be retrived
as the HTTP response.
In addition, the Aglets server has to be somehow capable of receiving
that HTTP-wrapped ATP request. Therefore, the Aglets server
can be configured so that it can receive an HTTP POST message with
the content type "x-atp" and can unwrap the ATP request. If it receives
an HTTP-wrapped ATP request, it sends an HTTP response in the same way.
Configuring a Sender
To send a HTTP tunneling request, you have to specify the HTTP proxy
host to be used.
- Open the Network configuration panel by selecting:
Options -> Network Preference
- Check the "Use HTTP Proxy" in the "HTTP Tunneling" panel.
- Type the host name and port number of the proxy server.
- Input the beginning string or ending string of the address
for which you do not want to use a proxy.
- Press the OK buton
Configuring a Receiver
To receive an HTTP tunneling request, a receiver has to be configured so
that it can receive an HTTP-wrapped ATP request.
- Open the Network configuration panel by selecting:
Options -> Network Preference
- Check the "Accept HTTP tunneling Request" in the "HTTP tunneling" panel
.
- Press the OK button.
Limitation of HTTP tunneling
Because the firewall allows only a one-way connection to the
outside, the dispatched aglet cannot fetch a class on demand. Make
sure that all necessary classes are stored in the stream and transferred
to the destination by making references to those classes inside the object.
Furthermore, it is impossible for an aglet to dispatch itself back into
the intranet through the firewall. To get back inside a firewall, an
aglet has a unique primitive, called retract, which lets
a client to "pull" the dispatched aglet from a remote site. In this way,
you can dispatch an aglet outside the firewall and get it back into the
intranet.
Security in Aglets
Security is essential to any mobile agent system because accepting a
hostile agent may lead to being harmed your computer or your privacy breaked.
This section gives an overview of the key security mechanisms provided
in the 1.0 release.
Note: Please report any security problems you uncover to
the Aglets team listed at the bottom of this page. In this 1.0
release, some security problems should be anticipated.
Environment Variables and File Protection
The Aglets library is loaded from Java classes on the CLASSPATH.
The AGLET_PATH is the default lookup path for aglet creation.
The AGLET_EXPORT_PATH directory contains the fetchable aglet classes.
Make sure that all these directories are properly protected, i.e. that
only authorized users have write access. Otherwise it would be possible
to replace security-relevant Java classes of the Aglets Workbench,
such as ibm.atp.agentsystem.aglets.AgletsSecurity, and thus to
bypass security checks.
Only classes that are not on the CLASSPATH can be transferred and
only classes which are on AGLET_EXPORT_PATH are fetchable from
remote sites.
Aglets stores its security settings in
$HOME/.aglets/security/{trusted|untrusted}.
Again, this file must be properly protected.
Aglet Properties
The following information is associated with each aglet:
Aglet Instance | Aglet Class |
identity | Class name |
owner id | code base |
creation date | version |
trust | |
Aglets are identified by their code base and identity. The owner
of the aglet is identified by his/her user name and e-mail address.
Trust
Aglets may have different levels of trust.
In ASDK1.0, aglets are classified as either
trusted or untrusted.
Aglets are considered to be trusted if their
code base is local, that is, the class definition is loaded from
trusted host, that is, your local hard disk.
(e.g., file:/SomePath/someClass).
All other aglets are
treated as untrusted. Examples of untrusted aglets
are aglets that come from an external server or that are generated as
instances of an aglet class located at a remote site. Note
that an aglet with code base
atp://localhost/SomePath/SomeClass is treated as untrusted!
A trusted aglet has the privilege of creating another trusted aglet on
the same aglet server.
In general, the access control setting is specified more strictly
for an untrusted aglet than for a trusted one.
Security Preferences (Policy Database)
A user can specify specific authorizations for trusted and untrusted
aglets that govern read/write access to files and
libraries, object instantiation, and window access and warning. These
security options are defined for each aglet security category (trusted
and untrusted) and are stored in the files
- $HOME/.aglets/security/trusted (or $JAVA_HOME if there is no $HOME) and
- $HOME/.aglets/security/untrusted (or $JAVA_HOME if there is no $HOME).
Note: Addition or removal of rights should only take
place via utilities described below. It is highly recommended that the
above security profile files should not be modified directly, for example,
by using an editor.
Again, the above files have to have proper file access protection.
Otherwise, one could modify the privileges of untrusted aglets to include
file write access to any subdirectory. In general,
aglets should never have file write access to $HOME/.aglets, $CLASSPATH,
$AGLET_PATH, and $AGLET_EXPORT_PATH.
For each security category, the following resource categories are
currently supported:
FileSystem, Network, Property, and Others. In the following, we
describe a graphical user interface for setting security
options.
Setting Security Options
File Access Control
Tahiti controls the access to the local file system. For each
category of aglets, a file access path specified by a list of
directory path names defines the part of the file system that is
accessible in either read or read/write mode.
Network Access Control
Specified <port number>s are kept in the Listen list box.
Aglets server in the current aglet security category is enabled to listen to
these ports. Specified <hostname:port number>s are kept in the
Connect list box. Aglets server in the current aglet security category
is enabled to connect to these ports.
Properties
Not implemented yet.
However, as a work-around, is is possible to control
access to properties by inserting appropriate rules in the security
profiles. The following table gives examples:
Rule | Meaning |
property.access.java.version=true | Java version number |
property.access.browser=true | ??? |
Note: Inserting the rule property.access.*=true
gives an aglet of that category the right to read all system
properties. These include sensitive information such as:
Key | Meaning |
java.home | Java installation directory |
java.class.path | Java classpath |
user.name | User account name |
user.home | User home directory |
user.dir | User home directory |
It is highly recommended that untrusted aglets should not have access
to the above properties.
Others
- Warning Message
- Open Window
- JDBC
- RMI Client
- RMI Server access
When the box labeled "Warning Message on Aglet Windows" for a trusted aglet
is checked, a warning window
appears at the bottom of the window when the aglet performs an
operation, even if it was created as a trusted aglet.
When the box labeled "Enable to Open Windows" for an untrusted is
checked, untrusted aglets are allowed to open windows.

Security Manager (ibm.aglets.AgletsSecurityManager)
The Aglet Security Manager is part of the security concept of the Java
language. The Java Security Manager contains a number of methods
that are intended to be called to check specific types of
security-sensitive actions. The following table provides a list of
the public methods with their intended uses:
Method | Description |
checkAccess | Check whether a thread or thread group can modify the thread group. |
checkExit | Checks whether the Exit command can be executed. |
checkExec | Checks whether the system commands can be executed. |
checkLink | Checks whether dynamic libraries can be linked (used for native code). |
checkRead | Checks whether a file can be read from. |
checkWrite | Checks whether a file can be written to. |
checkConnect | Checks whether a network connection can be created. |
checkListen | Checks whether a certain network port can be listened to for
connections. |
checkAccept | Checks whether a network connection can be accepted. |
checkProperties | Checks whether the System properties can be accessed. |
checkTopLevelWindow | Checks whether a window must have a special warning. |
checkPackageAccess | Checks whether a certain package can be accessed. |
checkPackageDefinition | Checks whether a new class can be added to a
package. |
checkSetFactory | Check whether an Applet can set factory objects. |
By default, aglets cannot perform most of the above actions, and
windows opened by untrusted aglets have a warning.
The Java SecurityManager class itself is not intended to be used
directly. In the AWB, it is subclassed and installed as the
AgletsSecurityManager and enforces the desired security policy. The
AgletsSecurityManager provides the following checks:
- checkCreateAgletContext();
- Checks whether the current execution can create a new
agletContext.
- checkAgletContextAccess(AgletContext cxt);
- Checks whether the current execution can acces the
agletContext.
- checkAgletAccess(Aglet aglet);
- Checks whether the specified aglet can be accessed.
- checkCreate(URL agletURL, String name);
- Checks whether the current thread is allowed to access the
aglet.
- checkClone(Aglet aglet);
- Checks whether the current execution can clone the aglet.
- checkRevert(Identity who, Aglet aglet, URL uRL);
- Checks whether the aglet can be retracted by the remote
host.
- checkRetract(URL agletURL, AgletID aid);
- Checks whether the aglet can retract the aglet.
- checkReceive(Identity who, Identity manufacturer, AgletID id, URL from);
- Checks whether the aglet can be received.
- checkDispose(Aglet aglet);
- Checks whether the current execution can dispose of the aglet.
- checkDispatch(Aglet aglet, URL uRL);
- Checks whether the current execution can dispatch the aglet.
- checkDeactivate(Aglet aglet, long i);
- Checks whether the current execution can deactivate the aglet.
- checkActivate(AgletIdentifier agletIdentifier);
- Checks whether the current execution can activate the aglet.
- checkSubscribeMessage(String msg);
- Checks whether the current execution can subscribe to
multicast messages.
- checkMulticastMessage(Message msg);
- Checks whtether the current execution can send a
multicast message to the aglet.
- checkMessage(Aglet aglet, Message msg);
- Checks whtether the current execution can send a
message to the aglet.
- checkPackageTransfer(String string);
- Checks whether the current execution can transfer the object
of the specified class name.
Possible Attacks
- Creates new sub-agents recursively until the JVM is out of
memory. Unable to shutdown Tahiti.
- An aglet that cannot be disposed of(?)
- Gets a list of all AgletProxies in the current AgletContext,
and disposes of/dispatches/deactivates/clones each.
To be rechecked.
Building Applications with Aglets
The Aglets library provides developers with a set of APIs to build and
configure your applications using Aglets technology. With one of these APIs,
an application can have its own configured viewer, import a portion of server
facilities, or create and launch an aglet without server capabilities.
Scenarios
There are several scenarios for building an application by using Aglets
technology.
While a server can host running aglets, a client can create and control
an aglet remotely without any aglet context. Applets can be on either
a server or a client, although it is impossible to dispatch an aglet to
an applet.
Aglet Components Only
This typical scenario does not require any additional APIs.
The application only consists solely of set of aglets built on an
Aglets API.
Such a configuration normally includes a stationary agent that has
privileged access to local resources such as databases and file systems,
and provides services for incoming aglets.
The classes used to define the stationary agent can be from either
local disk (CLASSPATH) or a given codebase. If it's loaded from
CLASSPATH, no security limitation is enforced by the security manager,
the aglet has the highest privileges, that is, it can do whatever it
wants. If it is loaded from a codebase, appropriate security enforcement
will be applied in accordance with its identity.
With this configuration, an incoming aglet normally gains access to
services via message passing. Then, it can leave for the next server
along with the result obtained in the server, or send it to the home
server by remote message passing and die. Message passing is also under
the control of the security manager and a receiver aglet can also deny a
request.
The server can be also configured so that it allows a limited set
of aglets (trusted or untrusted in current version) to access the local
resources and services.
In this case, for example, an aglet may open a direct connection to a
database and issue a SQL request. This gives an aglet great
flexibility in an using the server resources, while is also creates
the risk that an aglet may misuse or abuse these resources,
and eventually may cause the system to misbehave or even crash.
Customized Aglet Viewer
A viewer of an Aglets server can be configured by using the context event
and listener API, and a server can define its own viewer.
Such a viewer may provide a sophisticated management tool for an
administrator, or a easy-to-use and application-specific
interface for end users.
For example, a good administration tool would provide comprehensive
ways of creating service aglets, monitoring visiting aglets, and
disposing of them if necessary. Furthermore, the viewer can provide
service for an incoming aglet in response to its arrival. For example,
a gateway server may offer an incoming aglet the itinerary object
for a further trip inside the gateway when it arrives.
On the other hand, the viewer can be customized for users or
specific services. For example, a desktop-like interface may
use an icon for aglets and drag anddrop operations to manipulate them
for people who is familiar with PCs, while a kiosk for novice
users will define a single-click, Web style interface.
Applications embedding Aglets Server Facility
This scenario is a typical way of adding the functionality of
accepting and hosting aglets into a traditional application.
For example, a simple groupware application may use Aglets
to provide service and to use it, or to communicate with
members. It would be inadequate for such applications to just use
the aglet server as it is, even if the developer can
implement its own viewer.
The Aglets Server API allows developers to embed and bootstrap
the aglets server in their applications, and to configure
the server's SecurityManager, Persistence, Viewer, and so on.
Furthermore, an application may not want to accept incoming
aglets while it is creating an aglet or dispatching and retracting
it to obtain a service. The Server API allows an application to run
the Aglets runtime library without daemon capability for this purpose.
Client Applications
A client application has no server facility; it only has
communication facilities for creating and controling an aglet remotely,
or for sending a remote message. Therefore, this configuration requires
fewer resources to use aglets and reduce security threats, because
it does not download any bytecode, although it can still take advantage
of mobile agents on the server sides.
For example, the console of a massive network management system
may not have to install the server facility. The console application,
which typically has a client capability, can create a monitor
aglet on a machine, and let a detective aglet roam multiple machines
and send information back to the console.
Server API Overview
Aglets provides developers with a set of APIs that support several
kinds of server scenario.
The ContextEvent class and ContextListener interface enable you to monitor
the activities of aglets and to take actions in response to these
activities. The typical application of this API is "AgletViewer"
which displays a list of aglets running in the server and lets you
control them by disposing of them or dispatching them, for example.
The Aglets Server interface makes it possible to write an
application capable of hosting, receiving, and dispatching aglets.
With this interface, you can take advantage of mobile agent technology in
one's application without running an independent, separate server program
such as Tahiti.
- com.ibm.aglet.event.ContextListener
-
The ContextListener interface defines a set of methods to be called when
a context related event is occured. The Listener object can be set by
calling the AgletContext.addContextListener(ContextListener)
primitive. The contextStarted method is called when
the context is started, and should define the initialization process
to validate the context. The contextShutdown is called when
the context is shutdown, and is supposed to perform a finalization process
to invalidate the context and release the resources used by the context.
Note that if you add the context listener after the context is started,
or if you remove the context before the context is shutdown,
these two methods will not be called.
The other methods are for notification of the activities of aglets.
It is guaranteed that when an event occurs, the proxy of
an aglet given as a parameter in the ContextEvent is still available
via the getAgletProxies() primitive. If an aglet is being
disposed of, or dispatched, however, the instance of the aglet is in the
middle of an invalidating process and may have an intermediate state.
Therefore only the limited operations listed below are allowed to
be performed, and check methods such as isValid() and
isRemote etc., may not return correct values.
- AgletInfo AgletProxy.getAgletInfo()
- AgletID AgletProxy.getAgletID()
- String getAgletClassName();
package com.ibm.aglet.system;
public interface ContextListener {
public void contextStarted(ContextEvent ev);
public void contextShutdown(ContextEvent ev);
public void agletCreated(ContextEvent ev);
public void agletCloned(ContextEvent ev);
public void agletArrived(ContextEvent ev);
public void agletActivated(ContextEvent ev);
public void agletReverted(ContextEvent ev);
public void agletDisposed(ContextEvent ev);
public void agletDispatched(ContextEvent ev);
public void agletDeactivated(ContextEvent ev);
public void agletStateChanged(ContextEvent ev);
public void showDocument(ContextEvent ev);
public void showMessage(ContextEvent ev);
}
agletStateChanged() is called when an aglet changes its state
by, for example, calling Aglet.setText(String); primitive.
showDocument() is called when an aglet calls
the Aglet.showDocument(URL) primitive to request that
the specified document be shown.
It is left to the context implementor to decide whether or how to
implement the showDocument method. The default implementation of
Tahiti launches an external web browser, but another implementation may
use an internal browser written in Java to load and display an HTML
document.
- com.ibm.aglet.event.ContextEvent
- The ContextEvent class is an Event class, which is deliverered to
listeners when the state of the context or aglets in it changes.
package com.ibm.aglet.system;
public class ContextEvent extends AgletEvent {
public static final int CONTEXT_FIRST = 1000;
public static final int CONTEXT_LAST = 1012;
public static final int STARTED = CONTEXT_FIRST; // 1000
public static final int SHUTDOWN = CONTEXT_FIRST + 1; // 1001
public static final int CREATED = CONTEXT_FIRST + 2; // 1002
public static final int CLONED = CONTEXT_FIRST + 3; // 1003
public static final int DISPOSED = CONTEXT_FIRST + 4; // 1004
public static final int DISPATCHED = CONTEXT_FIRST + 5; // 1005
public static final int REVERTED = CONTEXT_FIRST + 6; // 1006
public static final int ARRIVED = CONTEXT_FIRST + 7; // 1007
public static final int DEACTIVATED = CONTEXT_FIRST + 8; // 1008
public static final int ACTIVATED = CONTEXT_FIRST + 9; // 1009
public static final int STATE_CHANGED = CONTEXT_FIRST + 10; // 1010
public static final int SHOW_DOCUMENT = CONTEXT_FIRST + 12; // 1012
public static final int MESSAGE = CONTEXT_FIRST + 13; // 1013
public static final int NO_RESPONSE = CONTEXT_FIRST + 14; // 1014
public Object arg = null;
public AgletContext getAgletContext();
public AgletProxy getAgletProxy();
public String getMessage();
public String getText();
public URL getDocumentURL();
public ContextEvent(int id, Object context, AgletProxy target, Object arg);
public ContextEvent(int id, Object context, AgletProxy target);
}
- ibm.atp.daemon.Daemon Class
-
The ibm.atp.daemon.Daemon class for receiving incoming
aglets and accepting remote messages to the aglets resides in the local
context. When created, it opens the server socket, listens to the
ATP requests and forwards them to the AgentRequestHandler associated
with the agent system type specified in the request.
The port number can be specified when a daemon object is created. This
may fail if the same number is already in use or the user is not allowed
to open the number. (In Unix-based systems,
for example, normal users are not allowed to open ports lower than 1024)
Finally, the start(String agentSystem) primitive
creates the appropriate Handler object for the given agentSystem
and starts the daemon.
package ibm.atp.daemon;
public Daemon() {
public Daemon();
public void setAccessLogStream(OutputStream out);
public void setAccessLogFile(String filename) throws IOException;
public void setErrorLogStream(OutputStream out);
public void setErrorLogFile(String filename) throws IOException;
public void setMessageLogStream(OutputStream out);
public void setMessageLogFile(String filename) throws IOException;
public void message(long time, String msg);
public void error(InetAddress host, long time, String err, String reason);
public void access(InetAddress host, long time, String requestLine,
int statusCode, String misc);
public void start(String agentSystem);
public AgentRequestHandler getRequestHandler(String agentSystem);
}
- com.ibm.aglet.system.AgletRuntime Class
-
The com.ibm.aglet.system.AgletRuntime class provides an interface for
creating and managing the context. The only instance of this class is
automatically created by the runtime, and neither an application nor
an aglet can create an object of this class. Instead, an application
must use getAgletRuntime() primitive to obtain the reference
to the runtime object.
createAgletContext(String name) primitive creates
a new instance of the runtime with the given name. If there is
an existing context with the same name, the primitive throws
an IllegalArgumentException. These contexts created in the runtime
can be obtained by either the getAgletContext(String name)
or the getAgletContexts() primitive.
removeAgletContext(AgletContext cxt) removes the specified
context from the internal context table.
A living AgletContext can be removed from the runtime table
without shutdown. Such a context becomes invisible, and
cannot be accessed either remotely or locally. This can be
used to create a sort of "private" context into which no aglet
be dispatched.
class AgletRuntime {
AgletRuntime getAgletRuntime();
public AgletContext createAgletContext(String name);
public AgletContext getAgletContext(String name);
public void removeAgletContext(AgletContext cxt);
public AgletContext[] getAgletContexts();
}
- AgletsSecurityManager Class
T.B.D.
Client API
Aglets Class
The com.ibm.aglet.system.Aglets class lets an application program create
and control an aglet remotely without requiring the AgletContext.
class Aglets {
public static AgletProxy createAglet(String contextAddress,
URL codebase,
String classname,
Object init);
public static AgletProxy getAgletProxy(String contextAddress, AgletID id);
public static AgletProxy[] getAgletProxies(String contextAddress);
}
You are not required to do the bootstrapping for client applications.
public void main(String args[]) throws Exception {
String contextAddress = "atp://host.name:434/contextName";
AgletProxy proxy = Aglets.createAglet(contextAddress, null,
"your.Aglet", null);
proxy.sendMessage(new Message("buy", "jewel"));
AgletProxy proxies[] = Aglets.getAgletProxies(contextAddress);
// dispose all aglets
for (int i=0; i < proxies.length; i++) {
proxies[i].dispose();
}
}
Bootstrapping the Server
For the Aglet runtime to be able to create AgletContexts,
to accept incoming aglets and to host aglets,
a bootstrapping application is required to properly initialize
the system and start up the daemon. To do this, the application
program must follow the steps below:
- Initialize the Daemon and obtain the daemon object.
- Initialize the Aglet runtime system and obtain the runtime object.
- Create a AgletContext with/without name.
- Create a ContextListener for the context and add the listener
to it.
- Start the daemon object if you want to accept incoming requests.
- Start the context.
- From here on, you can make use of the Aglets facility.
The following example shows how to bootstrap the daemon and Aglets runtime.
public class MyServer {
static public void main(String args[]) {
//
// Create a daemon object and initialize it with arguments
//
Daemon daemon = Daemon.init(args);
//
// Obtain a runtime object and initialize it with arguments
//
AgletRuntime runtime = AgletRuntime.init(args);
//
// Creates a named context. To dispatch to this context, you have to
// specify a destination such as "atp://aglets.trl.ibm.com:434/test"
//
AgletContext cxt = runtime.createAgletContext("test");
ContextListener listener = new ContextAdapter () {
public void agletArrived(ContextEvent ev) {
AgletProxy proxy = ev.getAgletProxy();
try {
System.out.println("Aglet is arriving."+
proxy.getAgletInfo());
} catch (InvalidAgletException ex) {
ex.printStackTrace();
}
}
public void agletDispatched(ContextEvent ev) {
AgletProxy proxy = ev.getAgletProxy();
try {
System.out.println("Aglet is leaving."+
proxy.getAgletInfo());
} catch (InvalidAgletException ex) {
ex.printStackTrace();
}
}
}
cxt.addContextListener(listener);
//
// Create a daemon initialized with args
//
daemon.start("aglets");
//
// Start a context
//
cxt.start();
AgletProxy myAglet = cxt.createAglet(null, "MyAglet", null);
myAglet.sendMessage(new Message("startTrip"));
}
}
Properties in Aglets
Aglets Properties
The following table contains a list of properties typically used by the Aglets
runtime library for configuration.
Property Name | Description | Example |
aglets.class.path |
Specifies the default lookup path for a codebase. This is used when a null
value is given as a codebase in the AgletContext.createAglet(..)
primitive.
|
/usr/local/AWB/Aglets/public:/myhome/public
C:\AWB\Aglets\public:D:\myaglets\public
|
aglets.export.path
|
Specifies the directory containing classes that can be fetched from
a remote server. (Available for public access.)
|
/usr/local/AWB/Aglets/public:/myhome/public
C:\AWB\Aglets\public:D:\myaglets\public
|
aglets.viewer |
Specifies the class name that is used for the server.
The class must implement a ContextListener interface.
|
ibm.aglets.tahiti.Tahiti
|
ATP Properties
The following table contains a list of properties typically used by the ATP
transport layer for configuration.
Property Name | Description | Example |
atp.useHttpProxy
|
Turn on and off the http proxy.
|
true/false
|
atp.http.proxyHost
|
Host
|
firewall.ibm.com
|
atp.http.proxyPort
|
Port number
|
8080
|
atp.noProxy
|
The proxy is not used for the hosts whose addresses start with the string
specified here
|
ibm.com
|
Tahiti Properties
The following table contains a list of properties typically used by the Tahiti
viewer for configuration.
Property Name | Description | Example |
tahiti.browser_command |
openurl |
Specifies the command to launch the browser
|
Other Properties
T.B.D.
Itinerary and Patterns
T.B.D.
Copyright (C) 1997, 1998 IBM Corp. All rights reserved.
Aglets is a trademark of IBM Corp.
Java is a trademark of Sun Microsystems, Inc.