ProActive is built on top of a metaobject protocol (MOP) that permits reification of method invocation and constructor call. As this MOP is not limited to the implementation of our transparent remote objects library, it also provides an open framework for implementing powerful libraries for the Java language.
As for any other element of ProActive, this MOP is entirely written in Java and does not require any modification or extension to the Java Virtual Machine, as opposed to other metaobject protocols for Java {Kleinoeder96}. It makes extensive use of the Java Reflection API, thus requiring JDK 1.1 or higher. JDK 1.2 is required in order to suppress default Java language access control checks when executing reified non-public method or constructor calls.
If the programmer wants to implement a new metabehavior using our metaobject protocol, he or she has to write both a concrete (as opposed to abstract) class and an interface. The concrete class provides an implementation for the metabehavior he or she wants to achieve while the interface contains its declarative part.
The concrete class implements interface Proxy and provides an implementation for the given behavior through the method reify:
public Object reify (MethodCall c) throws Throwable;
This method takes a reified call as a parameter and returns the value returned by the execution of this reified call. Automatic wrapping and unwrapping of primitive types is provided. If the execution of the call completes abruptly by throwing an exception, it is propagated to the calling method, just as if the call had not been reified.
The interface that holds the declarative part of the metabehavior
has to be a subinterface of Reflect
(the root interface
for all metabehaviors implemented using ProActive). The purpose of this
interface is to declare the name of the proxy class that implements the
given behavior. Then, any instance of a class implementing this interface
will be automatically created with a proxy that implements this behavior,
provided that this instance is not created using the standard
new
keyword but through a special static method:
MOP.newInstance
. This is the only required modification
to the application code. Another static method,
MOP.newWrapper
, adds a proxy to an already-existing
object; the turnActive
function of ProActive, for
example, is implemented through this feature.
Here's the implementation of a very simple yet useful metabehavior: for each reified call, the name of the invoked method is printed out on the standard output stream and the call is then executed. This may be a starting point for building debugging or profiling environments.
class EchoProxy extends Object implements Proxy { // here are constructor and variables declaration // [...] public Object reify (MethodCall c) throws Throwable { System.out.println (c.getMethodName()); return c.execute (targetObject); } } interface Echo extends Reflect { public String PROXY_CLASS= 'EchoProxy'; }
Instantiating an object of any class with this metabehavior can be
done in three different ways: instantiation-based, class-based or
object-based. Let's say we want to instantiate a
Vector
object with an Echo
behavior.
Standard Java code would be:
Vector v = new Vector(3);
ProActive code, with instantiation-based declaration of the
metabehavior (the last parameter is null
because
we do not have any additional parameter to pass to the
proxy):
Object[] params = {new Integer (3)}; Vector v = (Vector) MOP.newInstance('Vector', params, 'EchoProxy', null);
with class-based declaration:
public class MyVector extends Vector implements Echo {} Object[] params = {new Integer (3)} ; Vector v = (Vector) MOP.newInstance('Vector', params, null);
with object-based declaration:
Vector v = new Vector (3);
v=(Vector) MOP.newWrapper('EchoProxy',v);
This is the only way to give a metabehavior to an object that
is created in a place where we cannot edit source code. A typical
example could be an object returned by a method that is part of an
API distributed as a JAR file, without source code. Please note
that, when using newWrapper
, the invocation of
the constructor of the class Vector
is not
reified.
All the interfaces used for declaring
metabehaviors inherit directly or indirectly from
Reflect
. This leads to a hierarchy of metabehaviors
such as shown in the figure below.
Reflect Interface and sub-interfaces diagram
Note that ImplicitActive
inherits from
Active
to highlight the fact that implicit
synchronization somewhere always relies on some hidden explicit mechanism.
Interfaces inheriting from Reflect
can thus be
logically grouped and assembled using multiple inheritance in order to
build new metabehaviors out of existing ones.
Due to its commitment to be a 100% Java library, the MOP has a few limitations:
Calls sent to instances of final classes (which includes all arrays) cannot be reified.
Primitive types cannot be reified because they are not instance of a standard class.
Final classes (which includes all arrays) cannot be reified because they cannot be subclassed.
© 2001-2007 INRIA Sophia Antipolis All Rights Reserved