µCode comes with the following toy examples that demonstrate some of its capability:
The source code for the examples is found in the distribution under the directory
examples.
localhost,
localhost:2000, and localhost:3000. Running the
examples on different hosts consists straightforwardly of substituting the
three addresses above with the addresses of the hosts.
In all the examples, the command line arguments available for launching a server
from the command line are still available and
can be specified for the applications you are running. Thus, for instance, you
can append to the command lines below the option -debug on to each of the command lines
below (e.g., to provide me with more information in case you discovered a bug).
See the documentation
of mucode.util.Launcher for
a list of options.
mucode.abstractions.MuAgent.
It creates a mobile agent that continuously hops from one µServer
to another.
>java mucode.util.Launcher -port 2000In a different shell, start the program
BounceLauncher, found under
examples/MobileAgent:
examples/MobileAgent>java BounceLauncher localhost:2000 localhostThe two parameters on the command line are the addresses of the two µServer the mobile agent is bouncing between.
>java mucode.util.Launcher -port 2000 mucode: MuServer activated on port 2000 Bouncer: step 2 Bouncer: step 3 Bouncer: step 6 Bouncer: step 7 Bouncer: step 10 Bouncer: step 11 Bouncer: step 14 Bouncer: step 15In the shell where you started the application, you will see:
examples/MobileAgent>java BounceLauncher localhost:2000 localhost Spawning the bouncing agent. mucode: MuServer activated on port 1968 This is the main thread. Bouncer: step 0 Bouncer: step 1 This is the main thread. Bouncer: step 4 This is the main thread. Bouncer: step 5 This is the main thread. Bouncer: step 8 Bouncer: step 9 This is the main thread. This is the main thread. Bouncer: step 12 Bouncer: step 13 This is the main thread.
Bouncer extends the abstract class
AbstractBouncer and implements the interface
Performer, which in turn extends SuperPerformer. All these classes are automatically packaged with the
agent and shipped to destination, since the go method call in
Bouncer specifies that the full class closure must be computed
and migrated along with the agent. Ubiquitous classes, in this case those coming
from Java (e.g., java.lang.Object) and from µCode (e.g., mucode.abstractions.MuAgent)
are not shipped. A more realistic implementation for a mobile agent that
bounces only between two µServers would exploit a class caching scheme,
by publishing these classes at destination the first time,
and then sending only the agent's object.
i printed on the console, and the list of nodes to
visit, is retained from hop to hop.
>java mucode.util.Launcher -port 2000In a different shell, start the program
Provider, found in examples/Provider.
You may want to enable debugging this time, just to see what happens:
examples/Provider>java Provider -debug onIn a third shell, start the program
Linker, found in examples/RemoteDynamicLinking:examples/RemoteDynamicLinking>java Linker localhost:2000 localhostThe first parameter is the destination for
Linker, the second
parameter is the µServer acting as a code repository for the agent, from
which the missing classes will be downloaded.
Linker, nothing happens. In fact, the
Linker application just sends an agent (an instance of itself) on
the host specified as the first parameters and then terminates.Provider, you will see:examples/Provider>java Provider -debug on Exporting the classes... Classes exported. Shared class space: [ Toolkit Nail Hammer ] mucode: MuServer activated on port 1968 mucode: Connection accepted. Reconstructing the header... mucode: The connection contains a request for dynamic linking of class: Toolkit mucode: Contents of shared class space: [ Toolkit Nail Hammer ] mucode: Bytecode for Toolkit (932 bytes) sent. mucode: Connection accepted. Reconstructing the header... mucode: The connection contains a request for dynamic linking of class: Hammer mucode: Contents of shared class space: [ Toolkit Nail Hammer ] mucode: Bytecode for Hammer (263 bytes) sent. mucode: Connection accepted. Reconstructing the header... mucode: The connection contains a request for dynamic linking of class: Nail mucode: Contents of shared class space: [ Toolkit Nail Hammer ] mucode: Bytecode for Nail (259 bytes) sent.Finally, in the shell where you started the µServer, you will see:
>java mucode.util.Launcher -port 2000 mucode: MuServer activated on port 2000 Creating a Toolkit object Using a Hammer and a Nail from the Toolkit Using a Hammer and a Nail from the Toolkit Using a Hammer and a Nail from the Toolkit
Provider makes available the classes for remote linking by
explicitly loading them into the shared class space associated with the µServer it creates. Notice that Provider is allowed
to do that as it is a stationary thread that has been created within the Java
VM and thus its private class space automatically has access to classes within
the CLASSPATH directories. If Provider would have
been a thread created in the µServer because of a migration, it
would not have had access to the file system. Furthermore, remember that
remote ship, fetch, and dynamic linking operations
have access only to the shared class space of a µServer. Linker, there is no need to explicitly pull out the class
Toolkit from the shared class space. It gets automatically
retrieved and linked by the µCode class loader when Toolkit
must be resolved. DECLARED to FULLCLOSURE. No
dynamic linking will take place, because all the classes needed for the
execution of Linker (including Toolkit) will be
found at destination.
Injected, found in examples/Ship/Injected:
examples/Ship/Injected>java InjectedIn a different shell, start the program
Injector, found in examples/Ship/Injector:
examples/Ship/Injected>java Injector localhost
Injector just performs the ship operation and then
terminates. Thus, in the shell where you started Injector you will
see:
examples/Ship/Injector>java Injector localhost Sending the class Toolkit on localhost ... ... done. examples/Ship/Injector>In the shell where you started
Injected you will see:
examples/Ship/Injected>java Injected I need Toolkit.class to proceed with execution. I'll look on my host, until it comes... mucode: MuServer activated on port 1968 Waiting for the class ... Waiting for the class ... Waiting for the class ... Class Toolkit is now in my shared class space. Using a Hammer and a Nail from the Toolkit Using a Hammer and a Nail from the Toolkit Using a Hammer and a Nail from the Toolkit
ship is provided by the class mucode.abstractions.Relocator.
Injected must be checked
explicitly.
Injected application, still load classes
using the default class loader. For these threads, the µServer
acts only as a class repository, but does not affect the loading process. This
is why it's not possible to write simply
((Toolkit) c.newInstance()).perform();rather than using reflection in the more complicated
c.getMethod("perform", null).invoke(c.newInstance(), null);
The first call would go through the default class loader and look in the file
system, where Toolkit cannot be found. Instead, the first call
would have been possible for a thread that was created in the µServer,
e.g., as a consequence of a migration.
Provider, found in examples/Provider:
examples/Provider>java Provider -port 2000In a different shell, start the program
Fetcher, found in examples/Fetch:
examples/Fetcher>java Fetcher localhost:2000
Provider is run will look like:
examples/Provider>java Provider -port 2000 Exporting the classes... mucode: MuServer activated on port 2000In the shell where you run
Fetcher you will see:
examples/Fetch>java Fetcher localhost:2000 I need Toolkit.class to proceed with execution. I'm going to fetch it from localhost:2000 mucode: MuServer activated on port 1968 Waiting for the class ... Class Toolkit is now in my shared class space. Using a Hammer and a Nail from the Toolkit Using a Hammer and a Nail from the Toolkit Using a Hammer and a Nail from the Toolkit
fetch is provided by the class mucode.abstractions.Relocator.
ship example, in
Provider, the private class space coincides with the set of
classes that are available on the file system, through the default class
loader, as the thread associated with the Provider application
has not been created in a µServer.
Injected in the previous example,
Fetcher has to explicitly check for the presence of the class in
the shared class space, and then use reflection to use its members.
>java mucode.util.Launcher -port 2000In a different shell, start the program
Cloner, found under
examples/CopyThread:
examples/CopyThread>java Cloner localhost:2000The two parameters on the command line are the addresses of the two µServer the mobile agent is bouncing between.
>java mucode.util.Launcher -port 2000 mucode: MuServer activated on port 1968 Cloner active, i = 4 Cloner active, i = 5 Cloner active, i = 6 Cloner active, i = 7 Cloner active, i = 8 Cloner active, i = 9 Cloner active, i = 10 ...In the shell where you started the application, you will see:
examples/MobileAgent>java Cloner localhost:2000
Cloner active, i = 0 About to clone the Cloner... Cloner active, i = 1 Cloner active, i = 2 Cloner active, i = 3 Done. Cloner active, i = 4 Cloner active, i = 5 Cloner active, i = 6 Cloner active, i = 7 Cloner active, i = 8 Cloner active, i = 9 Cloner active, i = 10 Cloner active, i = 11 ...
copyThread is provided by the class mucode.abstractions.Relocator.
i, is retained at cloning time.
MuServer class can be specialized to provide shared resources, as
demonstrated in this mobile producer/consumer system. A server provides a
shared integer that provides synchronized access to two mobile threads that
rendez-vous on the server.
Server in a shell, found in examples/ResourceSharing/Server:
examples/ResourceSharing/Server>java ServerIn a different shell, start the program
Consumer, found in examples/ResourceSharing/Consumer:
examples/ResourceSharing/Consumer>java Consumer localhostIn a different shell, start the program
Producer, found in examples/ResourceSharing/Producer:
examples/ResourceSharing/Producer>java Producer localhost
Consumer and Producer will return right after they
are invoked, since they only send an agent on the µServer created
within the Server program. In the shell of the latter, you will
see:
examples/ResourceSharing/Server>java Server mucode: MuServer activated on port 1968 Consumer started Consumer waiting... Producer started Consumer awaken. Consumer retrieved 0 Producer produced 0 Consumer waiting... Producer produced 1 Consumer awaken. Consumer retrieved 1 Producer produced 2 Consumer retrieved 2 Producer produced 3 Consumer retrieved 3 Producer produced 4 Producer waiting... Producer awaken. Producer produced 5 Consumer retrieved 4 Consumer retrieved 5 Producer produced 6 Consumer retrieved 6 Consumer waiting... Consumer awaken. Consumer retrieved 7 Producer produced 7 Producer produced 8 Producer waiting... Consumer retrieved 8 Producer awaken. Producer produced 9 Producer terminated Consumer retrieved 9 Consumer terminated
ResourceServer extends MuServer
straightforwardly by providing a Hashtable field that can be used
by the threads hosted by the µServer to share objects.
main method of Producer starts remotely on
the µServer a new Producer thread. This thread first
acquires a handle to the µServer (which is an instance of
ResourceServer), and then writes a shared Integer
object in the hash table provided by the µServer. An analogous
behavior holds for Consumer.
SharedInteger), as if they were created within the µServer.
spawnThread method of the server. However, while producer
does not use any parameters, the consumer actually specifies as a parameter
the µServer from where it has been spawned and the time the thread waits before
performing another access to the shared resource. This demonstrate the
capability to instantiate threads remotely by using constructors other than
the default one.