|
|||||||||||
PREV NEXT | FRAMES NO FRAMES |
See:
Description
Packages | |
mandala.jacob | Specification and implementation of the Java Active Container of Objects concept. |
mandala.jacob.impl | Contains an implementation of the active map concept. |
mandala.jacob.remote | This package is dedicated to remote implementation of the active map concept. |
mandala.jacob.remote.gpf | Generic Protocol Framework (GPF) contains classes that may help implementors of new JACOb protocols. |
mandala.jacob.remote.gpf.rmi | GPF-RMI implementation of JACOb. |
mandala.jacob.remote.gpf.tcp | GPF-TCP implementation of JACOb. |
mandala.jacob.remote.gpf.udp | GPF-UDP implementation of JACOb. |
mandala.jacob.remote.rmi | Direct RMI implementation of JACOb. |
mandala.rami | Specification and implementation of the Reflective Asynchronous Method Invocation. |
mandala.rami.impl | Contains all classes related to Reflective Asynchronous Method Invocation. |
mandala.rami.transparency | The transparency package is the common place for anything related to transparent asynchronous method invocation. |
mandala.rami.transparency.semi | Semi-transparent asynchronous method invocation mechanism implementation. |
mandala.rami.transparency.total | Total-transparent asynchronous method invocation mechanism implementation. |
mandala.util | This package is a util package for anything in Mandala. |
This document is the API specification for the Mandala Platform.
This project is hosted by SourceForge (http://sf.net/projects/mandala)
The open source project (LGPL license) Mandala provides a new model to deal with both concurrent and distributed programming. Moreover, Mandala focuses on dynamism: objects do not have to be specifically written to be to be accessed asynchronously and remotely. Hence, in a distributed context, objects used asynchronously leads to parallelism. Mandala extends the well-known method invocation paradigm to asynchronous (and potentially remote) method invocation.
Two subpackages written in pure java code are the core of Mandala:
RAMI
for Reflective Asynchronous Method
Invocation which allows any public method of any Java object to be
invoked asynchronously. RAMI is highly customizable using the Factory
design pattern and provides different asynchronous policies such as
concurrent semantics (threaded and threadpooled policy) and single
threaded semantics (fifo and random policy). The subpackage mandala.rami
is the implementation of RAMI.
JACOb
for Java Active Container of Objects
which allows any public method of any object to be invoked
remotely. JACOb uses the concept of active container - modelized
in pi-calculus - which enables any object to be remotely accessible by
being inserted into a remote active container. JACOb can be used for
distributed applications programming, parallel programming, mobile agents
programming, aspect programming. JACOb uses the interfaces defined in
RAMI ensuring a common view between asynchronous objects and asynchronous
remote objects. The subpackage mandala.jacob
is the
implementation of JACOb.
Using Mandala leads to several advantages that can be divided into two subcategories:
Whereas threads are good entities for concurrent programming in imperative languages (such as C), I believe they are not good ones (and especially Java threads) for concurrent programming in object oriented languages.
For example, in Java, Thread requires a run() method to be defined which represents the thread behavior. Invoking this method produce the same result -- from a Java newbie point a view -- as invoking start(). Is is hard to understand that a Java Thread instance is not the *real* thread but only a (bad?) representation of it. Many problems with Java Threads have already been mentioned in the litterature (stop(), suspend()/resume(), scheduling and priorities which are OS dependent (no more green threads since the JDK 1.3), the thread swing model problem, etc.).
Several projects already dealt more or less with concurrency issues:
But I believe a radically different approach must be choosed:
ServerSocket ss = new ServerSocket(); while(true) { Socket socket = serverSocket.accept(); new Thread() { public void run() { serve(socket); } }.start(); }The problem is that the asynchronism is tied to the implementation, here, one thread per call. For performance reasons, it might be better to use a threads pool...
Another example, suppose you want to perform asynchronous input/output (of course, you may use the new Java IO package -- available since the JDK 1.4 -- for this purpose , but this example serves my speech): The "natural" synchronous code is:
InputStream is = ...; OutputStream os = ...; byte[] b = ...; int n = ...; while((n = is.read(b)) != -1) { os.write(b, 0, n); }which leads when using threads "naively" to something like:
while((n = is.read(b)) != -1) { new Thread() { public void run() { os.write(b, 0, n); } }.start(); }which is erroneous as you may have guessed: the byte buffer
b
is shared across multiple threads. Whereas a synchronized
section solves the problem it leads to really poor performance and breaks
the concurrency searched for: writers write while readers
read.
Asynchronism in Mandala is based on its RAMI
(Reflective Asynchronous Method Invocation) package which provides
asynchronous method invocations using the asynchronous reference
concept. Asynchronous references are the standard Java synchronous
references extension to the asynchronous world: an asynchronous reference
on an object allows any public method of this object to be invoked
asynchronously.
Asynchronous proxy are "sugar syntactic" mirror classes of standard classes which provides transparency in asynchronous (and potentially remote, see below) method invocation. An asynchronous proxy uses an asynchronous reference for the actual asynchronous method invocation mechanism implementation.
Using asynchronous references in the server example above leads to something like:
ServerSocket ss = new ServerSocket(); // Creates an asynchronous proxy on a 'Service' instance // which contains the serve() "business" method jaya.Service service = new jaya.Service(); while(true) { Socket socket = serverSocket.accept(); service.rami_serve(socket); // asynchronous call }
The advantages are the following:
ConcurrentSemantic
: asynchronous method
invocations may run concurrently on the same object. This semantic
has currently two implementations:ThreadedPolicy
: a thread per
calls implementation;
ThreadPooledPolicy
: a threads
pool implementation.
SingleThreadedSemantic
: asynchronous
method invocations are never run concurrently on the same
object. This semantic allows non-thread-safe objects to be used
asynchronously anyhow. Two implementations is provided as well:FifoPolicy
: a FIFO
implementation where methods are run in the order they are
invoked;
RandomPolicy
: a random
implementation where methods are run in a random order.
In the example above, the default semantic is used because no semantic are defined. If a threads pool implementation is required, the instantiation must be:
AsynchronousSemanticFactory asf = new ThreadPooledASFactory(); jaya.Service = new jaya.Service(asf);
Using asynchronous references in the asynchronous input/output example above leads to:
InputStream is = ...; OutputStream os = ...; // A FIFO semantic is required! AsynchronousSemanticFactory asf = new FifoASfactory(); // Gets an asynchronous proxy on the 'os' instance jaya.java.io.OuputStream ramios = (jaya.java.io.OuputStream) Framework.getSemiTransparentAsynchronousProxy(os, asf); int n = ...; FutureClient future; while(true) { byte[] b = new byte[n]; n = is.read(b); if (n == -1) break; future = ramios.rami_write(b, 0, n); } doSomething(); // During the output... // Using a FIFO semantic guarantees that everything is written // in order. Hence, when the last asynchronous method invocation // has terminated, we are sure everything has been done. future.waitUntilDone(); And, as you see, the problem is solved by using a FIFO asynchronous semantic and by the creation of a new byte buffer for each read()/write().
The use of asynchronous method invocation is quite natural and prevent
developers to deal with threads related problems such as scheduling,
priorities and canceling (stopping(), interrupting()). For example,
canceling an asynchronous operation is not performed same by a thread per
call implementation (where you just call interrupt() on the target
thread) than by a threads pool implementation call scheme (interrupt() is
erroneous!). In Mandala, canceling an asynchronous method invocation is
just a matter of invoking the method cancel()
on the Future
object returned. The actual
implementation does all the magic for you. All this asynchronous
implementation dependent issues are handled by the asynchronous reference
implementation used.
Naturally, Mandala extends asynchronous method invocation to asynchronous
remote method invocation using its JACOb
(Java Active Container of Objects) package which relies on RAMI
and on the active container concept. Any
objects can become remote and be used asynchronously. No more interface
to implements (like in RMI or in Corba), no class to extend: only
business code in your objects! Hence, your remote objects do not depend
on any particular technology.
JACOb uses the active container concept through the ActiveMap
implementation. The concept is very simple. An
active container is just a map which provides a call()
method to invoke method on its stored objects.
Consider the example below:
// Use JNDI to get a remote active map reference ActiveMap activeMap = null; String URL = "rmi://host/RMIActiveMap"; // may be LDAP // JNDI part try{ javax.naming.InitialContext context = new javax.naming.InitialContext(); activeMap = (RemoteActiveMap) context.lookup(URL); }catch(NamingException ne) { ... } // A library returns an object I want to use remotely java.math.BigInteger bi = library.foo(); // Get a global unique key Object key = StoredObjectReference.getGlobalUniqueKey(); // Insert 'bi' in the remote active map activeMap.put(key, bi); // Get a stored object reference on it StoredObjectReference sor = StoredObjectReference.getInstance(activeMap, key); // Get an asynchronous proxy on this stored object jaya.java.math.BigInteger i = jaya.java.math.BigInteger.getInstance(sor); // 'i' is now a proxy on the stored object 'bi' in 'activeMap' assert sor == (StoredObjectReference) i.getAsychronousReference(); assert activeMap.containsKey(sor.getKey()); // Our 'BigInteger' is remote whereas it has not be designed for it! assert activeMap instanceof RemoteActiveMap; // Invoke a method remotely and asynchronously FutureClient future = i.rami_isProbablePrime(CERTAINTY); doSomethingElse(); try{ boolean isPrime = future.waitForResult(); }catch(RemoteException e) { // Handle if necessary }
As you see, ActiveMap
extends the Map
interface - nothing to learn! RemoteActiveMap
is just an ActiveMap
remotely accessible. Then, we can insert an object into the active map
(here a BigDecimal
instance returned by a library)
using the put()
method. And then, the stored object is automatically remotely accessible
through the active container it resides in! Asynchronous remote method
invocation on stored objects are done using asynchronous proxies of the
RAMI package. Note that if you are the creator of the stored object,
things are simpler:
// Create a stored object transparently // (A new key is automatically created) jaya.java.math.BigInteger i = new jaya.java.math.BigInteger("1234567890", new SORFactory(activeMap)); // Invoke a method remotely and asynchronously FutureClient future = i.rami_isProbablePrime(CERTAINTY); doSomethingElse(); try{ boolean isPrime = future.waitForResult(); }catch(TransportException te) { // Handle if necessary }
As you see, Mandala does not require objects to be special as it is
commonly the case with other similar projects such as RMI (must
implements the java.rmi.Remote
interface and remote method
must declare java.rmi.RemoteException
in their throws
clause) or EJB (must inherit SessionBean
or
EntityBean
for example).
Hence, developpers write their objects as usual, and then use the Mandala framework to invoke their methods asynchronously (using RAMI)and remotely.
Features of the Mandala RAMI packages are:
Features of the Mandala JACOb packages are:
StoredObjectReference
which is an AsynchronousReference
implementation;
Features of the whole Mandala projects:
|
|||||||||||
PREV NEXT | FRAMES NO FRAMES |