Version 0.1
Danny B. Lange and Mitsuru Oshima © 1997
Chapter 3
Aglet Context
This chapter covers one of the key elements of J-AAPI, namely the AgletContext
interface. You will learn about the methods that an aglet can invoke in
its current context in order to create new aglets, retrieve aglets contained
in the same context, and much more.
The AgletContext interface is used by an aglet to get information
about its environment and to send messages to the environment and other
aglets currently active in that environment. It provides means for maintaining
and managing running aglets in an environment where the host system is
secured against malicious aglets.
The aglet context is typically created by a system that has a network daemon
whose job is to listen to the network for aglets. Incoming aglets are received
and inserted into the context by the daemon. Often, a user interface component
will provide a graphical or command line interface to the context.
An aglet belongs at any moment to one and only one context. It can gain
access to this context by means of its getAgletContext method:
context = getAgletContext();
The next section describes in detail methods for aglet creation and proxy
retrieval.
Aglet Creation
The only way you can properly instantiate an aglet is within a context.
The context provides all aglets with a uniform initialization and execution
environment. That is, an aglet relies on services provided by the context
to be properly instantiated and initialized. The createAglet method
is used to create new aglets.
public abstract AgletProxy createAglet(URL codeBase, String
code, Object init)
|
Creates an instance of the specified aglet class. The aglet's class
code file can be located on the local file system as well as on a remote
server. If the codeBase is null, the context will search
for the code in the local system's aglet search path (AGLET_PATH).
|
The createAglet method takes three arguments: codeBase,
code, and init.
-
codeBase specifies the base URL of the aglet class file, in
other words, the (possibly remote) directory that contains the aglet's
code. If this argument is null, then the directories specified
in the local host's aglet search path are searched. The aglet search path
works in a similar way to Java's class path. It is typically an environment
variable that specifies a list of directories to be searched for aglet
code files.
-
code gives the name of the file that contains the aglet's
compiled class code. This file is relative to the base URL of the aglet,
and cannot be absolute.
-
init is an object passed on to the aglet's onCreation
method.
When an aglet has been successfully created, it is inserted into the current
context and started (invocation of onCreation() followed by run()).
The method returns a handle (AgletProxy) for the new aglet as
soon as the aglet's constructor method finishes.
Code and Code Base
What do we mean by an aglet's code base? Well, it is one of the two arguments
necessary to locate the code for an aglet. The codeBase specifies
by a URL the (possibly remote) directory that contains the aglet's compiled
class code. The second argument, code, is always relative to the
base URL and translates the Java package dot notation (My.Package.SomeAglet)
into a proper path expression (My/Package/SomeAglet.class). The
following table gives some examples of code and code base, and how they
are translated into an absolute path for the code file that is actually
being loaded:
Code base
|
Code
|
Aglet code file actually loaded
|
file://c:/some/path
|
Demo
|
c:\some\path\Demo.class
|
atp://some.host/path
|
Demo
|
atp://some.host/path/Demo.class
|
http://some.host/path
|
Demo
|
http://some.host/path/Demo.class
|
http://some.host/path
|
examples.Demo
|
http://some.host/path/examples/Demo.class
|
So what exactly is the purpose of the code base? It plays an important
role as a reference point for the aglet's class loader. It is used not
only for aglet creation, but also by an aglet when it needs to instantiate
new classes (e.g., new SomeClass()) during its execution. In this
case, the aglet uses the code base to search for the code file of the indicated
class. Say the code base is file://c:/some/path; then the class
loader will look for the compiled code of SomeClass in the file
c:\some\path\SomeClass.class.
In the special case where the code base is null, the local host's
aglet search path is used (AGLET_PATH). The workings of this search
path are very similar as to those of Java's class path. It defines a list
of directories that are to be searched for the specified code file. The
following table gives two examples in which the code base is null:
Code base
|
Code
|
Aglet code file actually loaded
|
null
|
Demo
|
[AGLET_PATH]/Demo.class
|
null
|
Example.Demo
|
[AGLET_PATH]/examples/Demo.class
|
Notice that code residing in one of the directories specified in Java's
class path cannot move along with an aglet when it is dispatched. In other
words, you can regard the code that resides in one of these directories
as resident host code. Resident code will typically include the aglet system
itself. Obviously, it will also include other installed Java applications,
since these are often included in Java's class path when they are installed.
The rationale behind this is to provide an intuitive way of preventing
system/application software from moving along with the aglets. Say your
aglets are using JDBC to access local databases. It really would not be
practical to transfer JDBC code from host to host, since that code depends
on the type of database located on each host. Instead, the aglet should
rely on the local version of JDBC.
In the first example in this chapter, we will let the CodeBaseExample
aglet create an instance of an aglet whose class code is located in a file
named CodeBaseChild.class in the /aglets/aglet-book/examples
directory on a remote Web (http) server named www.trl.ibm.co.jp:
URL codeBase = new URL("http://www.trl.ibm.co.jp/aglets/aglet-book/examples");
getAgletContext().createAglet(codeBase, "agletbook.CodeBaseChild", null);
Full source code: CodeBaseExample.java
and CodeBaseChild.java.
In this case the code base is defined as the URL of the remote host, but
what if the code of CodeBaseChild is on the local machine instead?
Say the code is stored in the local path C:\some\path\CodeBaseChild.class.
The solution is simple, since the URL is a powerful abstraction for locations.
It covers a wide range of schemes including file, atp,
and http. If the code base is in the local file system, you should
use the file URL: file://c:/some/path.
The following table summarizes the relationship between the code base URL
and the location of the aglet's class file:
Code Base URL
|
Location
|
null
|
A directory in the aglet search path
|
file://c:/some/path
|
A directory in the local file system
|
atp://some.host/some/path
|
A directory on a remote aglet server using the atp protocol
|
http://some.host/some/path
|
A directory on a remote Web server using the http protocol
|
If the child's class file always shares code base with its creator, you
can increase the degree location transparency by replacing the child's
absolute code base with the current code base of the creator. This is particular
useful when you are developing and testing the aglets in a different environment
from the one where they will be deployed. Use the aglet's getCodeBase()
to get the current code base:
createAglet(getCodeBase(), "agletbook.ChildAglet", null);
Exercise
Copy CodeBaseChild.class to a directory on your local disk. Then
modify CodeBaseExample to instantiate the child from the local
file system. Finally, try to copy the class file into one of the directories
in your local aglet search path. Set the codebase in CodebaseExample
to null and confirm that the system is still able to find and instantiate
the aglet's code.
Initialization Argument
Notice that the aglet's onCreation method takes a single Object
argument. This argument is used to transfer initialization information
from the creator to its child. Let us demonstrate this feature by transferring
a string of text from the creator (InitExample) and the child
(InitChild).
import aglet.*;
public class InitExample extends Aglet {
public void run() {
try {
getAgletContext().createAglet(getCodeBase(), "agletbook.InitChild", "Hello World");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
InitExample passes the text string to the child through the third
argument in createAglet(). This string is received by InitChild's
onCreation method. The fact that this method is guaranteed to
complete its execution before run() is started means that it can
be trusted to initialize the text field before this field is printed
to the console in the run method. Notice that it is necessary
to cast the generic init parameter to the actual type of the field
(String).
import aglet.*;
public class InitChild extends Aglet {
String text; // Uninitilized text field.
public void onCreation(Object init) {
// Initialize the text field...
text = (String)init;
}
public void run() {
// Print the initilized text field...
System.out.println("The text: \'" + text + "\'");
}
}
Full source code: InitExample.java
and InitChild.java.
Proxy Retrieval
In this section we will focus on methods that retrieve aglet proxies for
you. As you may, proxies play know an important role as convenient handles
for aglets. That is, you can use a proxy to gain access to and communicate
with its corresponding (possibly remotely located) aglet. We will cover
proxies in depth in the next chapter.
Next, we will demonstrate a number of ways in which you can retrieve proxies
from local as well as remotely located aglets.
Proxy Iterator
The first method we will take a closer look at is the getAgletProxies
method. This method allows you to iterate the entire set of aglets in the
current context.
public abstract Enumeration getAgletProxies()
|
Gets the proxies of all aglets in the current context. The resulting
list (enumeration) will also include currently deactivated aglets.
|
In this example we use the getAgletProxies method to list the
current set of aglets in the following format:
<No.> <Aglet identifier> <Code base> <Aglet class name>.
The identity, code base, and code name are readily available from the proxy.
That is, we can generate this list simply by iterating the set of proxies
and for each proxy retrieve the needed information (getIdentifier(),
getCodeBase(), and getAgletClassName() in the AgletProxy
class).
The getAgletProxies method returns an Enumeration of
proxies. Enumeration has two methods that support iteration: hasMoreElements()
and nextElement(). This excerpt from the ProxyListing
example shows how the list is iterated and how aglet information is retrieved
and printed on the console:
Enumeration e = getAgletContext().getAgletProxies();
int i = 1; // List counter.
while (e.hasMoreElements()) {
// Get the proxy.
AgletProxy proxy = (AgletProxy)e.nextElement();
// Print a line of aglet information.
System.out.print("No.: " + i++ + ": ");
System.out.print(proxy.getIdentifier() + " - ");
System.out.print(proxy.getCodeBase() + " - ");
System.out.println(proxy.getAgletClassName());
}
Full source code: ProxyListing.java.
Getting a Local Proxy
The context also has methods for retrieving the proxy of an aglet if you
know the aglet's identity and, if it is not residing in the current context,
its location. The first method we will present is for retrieving the proxy
of an aglet in the current context.
public abstract AgletProxy getAgletProxy(AgletIdentifier identity)
|
Gets a proxy for an aglet in the current context. The selected aglet
is specified by its identity.
|
To retrieve a proxy from the current context by the getAgletProxy
method, you have to know the exact identity of the corresponding aglet.
In the following example, we let an aglet create two other aglets. Because
one of these is told the identity of the other, it is able to retrieve
the proxy of the other and send it a message.
First, the parent aglet (RetrievalExample) creates a child (RetrievalChild1)
and stores the child's identifier:
AgletProxy proxy = getAgletContext().createAglet(getCodeBase(), "agletbook.RetrievalChild1", null);
AgletIdentifier aid = proxy.getIdentifier();
Next, the parent aglet creates a second child (RetrievalChild2),
to which it passes the identity (aid) of the first child:
getAgletContext().createAglet(getCodeBase(), "agletbook.RetrievalChild2", aid);
The behavior of the first child is very simple. With only the handleMessage
method implemented, it will respond to any message sent to it by printing
the message on the console:
public class RetrievalChild1 extends Aglet {
public boolean handleMessage(Message msg) {
// Print to the console that you received a message...
return true; // Yes, I handled the message.
}
}
The second child's onCreation method takes an aglet identifier
as its initialization argument. This identifier is stored in the second
child's private aid field and later used by the run method.
In run() the second child will use the aid field to retrieve
the proxy for the first child (also called its brother). Having
retrieved the proxy, it will send the "Hello brother" message
to the first child:
public class RetrievalChild2 extends Aglet {
private AgletIdentifier aid;
public void onCreation(Object init) {
// Now I know ID of my brother...
aid = (AgletIdentifier)init;
}
public void run() {
// Retrieves the proxy of my brother.
AgletProxy proxy = getAgletContext().getAgletProxy(aid);
// Sends him a message...
proxy.sendMessage(new Message("Hello brother"));
}
}
Full source code: RetrievalExample.java,
RetrievalChild1.java,
and RetrievalChild2.java.
Getting Remote Proxy
Now let us move on to a method that allows us to retrieve the proxy of
an aglet hosted in a remote context.
public abstract AgletProxy getAgletProxy(URL host, AgletIdentifier
identity)
|
Gets a proxy for an aglet in a remote context. The remote context is
identified by its URL, and the aglet is indicated by its identifier.
|
To get a proxy of an aglet located in a remote context by the getAgletProxy
method, you have to know the URL of the remote context and the exact identity
of the aglet. In the following example, we let an aglet create two aglets.
One of these aglets is dispatched to a remote context. Because the other
one is told of the location as well as the identity of the remote aglet,
it is able to retrieve the proxy of the remote aglet and send it a message.
First, the parent aglet (RemRetrievalExample) creates a child
(RetrievalChild1 is reused from the previous example), stores
the child's identifier, and dispatches it to a remote context:
AgletProxy proxy = getAgletContext().createAglet(getCodeBase(), "agletbook.RetrievalChild1", null);
AgletIdentifier aid = proxy.getIdentifier();
proxy.dispatch(destination);
Next, the parent aglet creates a second child (RemRetrievalChild2),
to which it passes the aglet URL (destination and aid)
of the dispatched child:
AgletURL url = new AgletURL(destination, aid);
getAgletContext().createAglet(getCodeBase(), "agletbook.RemRetrievalChild2", url);
The AgletURL class is defined as follows:
class AgletURL {
public URL url;
public AgletIdentifier aid;
public AgletURL(URL u, AgletIdentifier a) {
url = u; aid = a;
}
}
The second child's onCreation method takes an aglet URL as its
initialization argument. The aglet URL is stored in the second child's
private url field and is later used by the run method.
In run() the second child will use the url field to retrieve
the proxy for the remote aglet. Having retrieved the proxy, it will send
the "Hello brother" message to the remote aglet:
public class RemRetrievalChild2 extends Aglet {
private AgletURL url;
public void onCreation(Object init) {
// Now I know ID of my brother...
url = (AgletURL)init;
}
public void run() {
// Retrieves the proxy of my brother.
AgletProxy proxy = getAgletContext().getAgletProxy(url.url, url.aid);
// Sends him a message...
proxy.sendMessage(new Message("Hello brother"));
}
}
Full source code: RemRetrievalExample.java,
RemRetrievalChild1.java,
RemRetrievalChild2.java,
and AgletURL.java.