µCode in a Nutshell


The µCode distribution is made of three packages. 

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:

  1. Check whether C is a ubiquitous class, i.e. a class available on every µServer. Classes belonging to the Java API and to µCode are ubiquitous by default. Checking ubiquitous classes first prevents redefinition of their behavior.
  2. Search for C in the private class space associated with t in S. Threads created directly by applications and not as a consequence of migration are all associated with the same class space, managed by the default Java class loader.
  3. Search for C in the shared class space associated with S.
  4. If t is allowed to perform dynamic download, C is retrieved from the remote µServer specified by the user at migration time, and loaded.
  5. If C cannot be found, an exception is thrown.

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:

copyThread
Allows to copy a thread object from the current µServer to another one.
spawnThread
Allows to spawn a thread in another µServer, by using the set of classes specified by the user. The thread may optionally be started by passing some parameters.
shipClasses
Allows to ship a set of classes to the shared class space of another µServer. 
fetchClasses
Allows to fetch a set of classes from the shared class space of another µServer. 

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


© 2000, Gian Pietro Picco - Last modification: 07/09/00