The µCode distribution is made of three packages.
mucode contains the core of the µCode system, providing a minimalistic set
of primitives to build any higher-level mobility operation. mucode.util contains utilities to launch a µCode server by accepting
command-line options and, more important, mechanisms that complement the
reflection capabilities provided by Java, enabling to determine the full
class closure (including classes that are not declared in members, but only
within methods). mucode.abstractions contains higher-level abstractions built on top of µCode,
including primitives to relocate code and state in various ways, as well as an
implementation of a mobile agent. Understanding µCode involves understanding only three new concepts: groups, group handlers, and class spaces.
A group is the only unit of mobility in µCode. A group provides the programmer with a container which can be filled arbitrarily with classes and objects (including thread objects), and shipped altogether at destination. Classes and objects do not need to belong to the same unit of execution. Moreover, the programmer may choose to insert in the group only some of the classes that will actually be needed at destination, and let the system exploit remote dynamic linking for downloading the missing classes from a specified node.
The destination of a group is a µServer. A µServer is just an
abstraction of the µCode run-time support, and provides the basic mechanisms to
relocate code and state.
At destination, the mix of classes and objects must be extracted from the
group and used in some coherent way, possibly to generate a new unit of
execution. This is the task of the group handler, an object specified
by the programmer at group creation time, that is
instantiated and whose operations are automatically invoked at destination. Any
object can be a group handler. Programmers can
define their own specialized group handlers and, doing so, define their own mobility primitives. As
an example, mobile agents and other high-level primitives provided by µCode
in the mucode.abstractions package,
are implemented using a system-defined group handler.
While reconstructing the group, the system will need to locate classes and
make them available for the subsequent execution of the group handler. In
particular, the classes extracted from the group need to be placed into some name
space, in order to avoid name clashes with classes reconstructed from
other groups. This capability is provided by the
class space. The classes that have been shipped in the same group are all
placed in a private class space, associated with that group. However,
these classes can later be "published" in a shared class space
associated to a µCode server (a µServer), where they become available to
all the threads that execute within the µServer.
Class spaces play also a role in the resolution of class names at loading time.
When a class C needs to be resolved during execution of a thread t
managed by a µServer S, µCode's custom class loader is invoked to
perform the following steps:
The concepts above constitute the core of µCode, as provided by the
package mucode. Higher-level abstractions are bulit on top of these
concepts. Among them are the abstractions provided by the package mucode.abstractions.
The class Relocator provides the following primitives that
enable relocation of classes and
thread objects:
These operations allow to implement architectures exploiting mobility, but
not necessarily a mobile agent. For instance, it is straightforward to implement
a remote evaluation scheme by using spawnThread, or implement class
caching schemes by using shipClasses and fetchClasses.
Interestingly, all these operations are implemented themselves by using a group
(constructed and shipped by the corresponding methods in Relocator)
and a group handler, RelocationHandler.
A similar consideration holds for MuAgent, the implementation of the
mobile
agent paradigm provided by mucode.abstractions. The whole
code for MuAgent is shown below (only the overloaded version of go
with a simpler signature is omitted).
public abstract class MuAgent extends Thread implements GroupHandler, Serializable {
private transient MuServer server = null;
private static final String AGENTLABEL = "_MuAgent_";
public MuAgent(MuServer server) { this.server = server; }
public MuAgent() { super(); }
public final void go(String destination, String[] classNames,
String dynLink, boolean synch)
throws MuCodeCommunicationException, MuCodeClassLoaderException {
if (server == null) server = MuServer.getServer(this);
String agentClassName = this.getClass().getName();
Group group = server.createGroup(agentClassName, agentClassName);
group.addObject(AGENTLABEL, this);
group.addClasses(classNames);
group.setDynamicLinkSource(dynLink);
group.setSynchronousTransfer(synch);
group.ship(destination);
this.stop();
}
public final Thread unpack(Group group) throws MuCodeException {
MuAgent agent = (MuAgent) group.getObject(AGENTLABEL);
agent.server = group.getServer();
return agent;
}
public abstract void run();
}
The MuAgent defines the behavior of the mobile agent by
specifying both how the corresponding group must be constructed (in the body
of the go method) and also the behavior of the corresponding
group handler, by specifying how the group must be reconstructed at
destination (in the body of the unpack method).
Note how this implementation of a mobile agent, equivalent to many of those provided by current mobile agent systems, is obtained with just a handful of source code lines. The key point is that you could obtain your own flavor of mobile agent (e.g., a multi-threaded one) with an analogously small effort.
For more information and details about how to program with µCode, see the API documentation.