|
![]() |
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.
Vector v = new Vector(3);
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);
public class MyVector extends Vector implements Echo {} Object[] params = {new Integer (3)} ; Vector v = (Vector) MOP.newInstance("Vector", params, null);
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.
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: