Chapter 6. Component examples

Two examples are presented in this chapter: code snippets for visualizing the transition between active objects and components, and the 'hello world' from the Fractal tutorial. The programming model is Fractal/GCM, and one should refer to the Fractal documentation for more detailed examples.

6.1. From objects to active objects to distributed components

In Java, objects are created by instantiation of classes. With ProActive, one can create active objects from Java classes, while components are created from component definitions. Let us first consider the 'A' interface:

public interface A {

    public String bar(); // dummy method

}

'AImpl' is the class implementing this interface:

public class AImpl implements A {

    Service service;

    public AImpl() {
    }

    public String bar() {
        return "bar";
    }


}

The class is then instantiated in a standard way:

A object = new AImpl();

Active objects are instantiated using factory methods from the PAActiveObject class (see Chapter 6.1. Simple Computation And Monitoring Agent). It is also possible to specify the activity of the active object, the location (node or virtual node), or a factory for meta-objects, using the appropriate factory method.

A activeObject = (A) PAActiveObject.newActive(AImpl.class.getName(), // signature of the base class
        new Object[] {}, // Object[]
        aNode // location, could also be a virtual node
        );

As components are also active objects in this implementation, they benefit from the same features and are configurable in a similar way. Constructor parameters, nodes, activity, or factories, that can be specified for active objects, are also specifiable for components. The definition of a component requires 3 sub-definitions: the type, the description of the content, and the description of the controllers.

6.1.1. Type

The type of a component (i.e. the functional interfaces provided and required) is specified in a standard way: (as taken from the Fractal tutorial)

We begin by creating objects that represent the types of the application components. In order to do this, we have first to get a bootstrap component. The standard way to do this is the following one (this method creates an instance of the class specified in the gcm.provider system property or in the fractal.provider system property if the first one has not been set, and uses this instance to get the bootstrap component):

Component boot = Utils.getBootstrapComponent();

Then, we get the GCMTypeFactory interface provided by this bootstrap component:

GCMTypeFactory tf = GCM.getGCMTypeFactory(boot);

Next, we can create the type of the first component, which only provides a A server interface named 'a':

// type of the "a" component
ComponentType aType = tf.createFcType(new InterfaceType[] { tf.createFcItfType("a", "A", false,
        false, false) });

6.1.2. Description of the content

The second step in the definition of a component is the definition of its content. In this implementation, this is done through the ContentDescription class:

ContentDescription contentDesc = new ContentDescription(AImpl.class.getName(), // signature of the base class
    new Object[] {} // Object[]
);

6.1.3. Description of the controllers

Properties relative to the controllers can be specified in the ControllerDescription:

ControllerDescription controllerDesc = new ControllerDescription("myName", // name of the component
    Constants.PRIMITIVE // the hierarchical type of the component
// it could be PRIMITIVE or COMPOSITE
);

Eventually, the component definition is instantiated using the standard Fractal/GCM API. This component can then be manipulated as any other Fractal/GCM component.

PAGenericFactory componentFactory = Utils.getPAGenericFactory(boot);
Component component = componentFactory.newFcInstance(aType, // type of the component (defining the client and server interfaces)
        controllerDesc, // implementation-specific description for the controller
        contentDesc, // implementation-specific description for the content
        aNode // location, could also be a virtual node
        );

6.1.4. From attributes to client interfaces

There are 2 kinds of interfaces for a component: those that offer services, and those that require services. They are named respectively server and client interfaces.

From a Java class, it is fairly natural to identify server interfaces: they (can) correspond to the Java interfaces implemented by the class. In the above example, 'a' is the name of an interface provided by the component, corresponding to the A Java interface.

On the other hand, client interfaces usually correspond to attributes of the class, in the case of a primitive component. If the component defined above requires a service from another component, say the one corresponding to the Service Java interface, the AImpl class should be modified. As we use the inversion of control pattern, a BindingController is provided, and a binding operation on the 'requiredService' interface will actually set the value of the 'service' attribute, of type Service.

First, the type of the component is changed:

// type of the "a" component
ComponentType aType = tf.createFcType(new InterfaceType[] {
        tf.createFcItfType("a", "A", false, false, false),
        tf.createFcItfType("requiredService", "A", true, false, false) });

The Service interface is the following one:

package org.objectweb.proactive.examples.components.helloworld;

public interface Service {
    void print(String msg);
}

And the AImpl class is:

public class AImpl implements A {

    Service service;

    public AImpl() {
    }


    // implementation of the A interface
    public void foo() {
        service.print("Hello World"); // for example
    }

    // implementation of BindingController
    public Object lookupFc(final String cItf) {
        if (cItf.equals("requiredService")) {
            return service;
        }
        return null;
    }

    // implementation of BindingController
    public void bindFc(final String cItf, final Object sItf) {
        if (cItf.equals("requiredService")) {
            service = (Service) sItf;
        }
    }

    // implementation of BindingController
    public void unbindFc(final String cItf) {
        if (cItf.equals("requiredService")) {
            service = null;
        }
    }
}

6.2. The HelloWorld example

The mandatory helloworld example (from the Fractal tutorial) shows the different ways of creating a component system (programmatically and using the ADL), and it can easily be implemented using ProActive.

6.2.1. Set-up

You can find the code for this example in the package org.objectweb.proactive.examples.components.helloworld in the ProActive distribution.

The code is almost identical to the Fractal tutorial's example.

The differences are the following:

  • The reference example is provided for level 3.3 implementation, whereas this current implementation is compliant up to level 3.2: templates are not provided. Thus, you will have to skip the specific code for templates.

  • The newFcInstance method of the GenericFactory interface, used for directly creating components, takes 2 implementation-specific parameters. So you should use the org.objectweb.proactive.component.ControllerDescription and org.objectweb.proactive.component.ContentDescription classes to define ProActive/GCM components. (It is possible to use the same parameters than in Julia, but that hinders you from using some functionalities specific to ProActive, such as distributed deployment or definition of the activity).

  • Components can be distributed

  • the ClientImpl provides an empty no-args constructor.

6.2.2. Architecture

The helloworld example is a simple client-server application, where the client (c) and the server (s) are components, and they are both contained in the same root component (root).

Another configuration is also possible, where client and server are wrapped around composite components (C and S).

Client and Server wrapped in composite components (C and S)

Figure 6.1. Client and Server wrapped in composite components (C and S)


6.2.3. Distributed deployment

This section is specific to the ProActive/GCM implementation, as it uses the deployment framework of this library.

If the application is started with (only) the parameter 'distributed', the ADL used is 'helloworld-distributed-no-wrappers.fractal', where virtualNode of the client and server components are exported as VN1 and VN2. Exported virtual node names from the ADL match those defined in the deployment descriptor 'deployment.xml'.

One can of course customize the deployment descriptor and deploy components onto virtually any computer, provided it is connectable by supported protocols. Supported protocols include LAN, clusters and Grid protocols (see Chapter 15. XML Deployment Descriptors).

[Note] Note

This example has been written using the old deployment descriptors. However, it is obviously possible (and recommended) to write it using the new GCM Deployment descriptors. Besides, this examples will probably be updated with the new deployment version in the future.

Have a look at the ADL files 'helloworld-distributed-no-wrappers.fractal' and 'helloworld-distributed-wrappers.fractal'. In a nutshell, they say: 'the primitive components of the application (client and server) will run on given exported virtual nodes, whereas the other components (wrappers, root component) will run on the current JVM.

Therefore, we have the two following configurations:

Without wrappers, the primitive components are distributed

Figure 6.2. Without wrappers, the primitive components are distributed


With wrappers only the primitive components are distributed

Figure 6.3. With wrappers only the primitive components are distributed


By default, bindings are not optimized. For example, in the configuration with wrappers, there is an indirection that can be costly, between the client and the server. However, optimizations allow to shortcut communications, while still allowing coherent dynamic reconfiguration. It is the same idea than in Julia, but we are dealing here with distributed components. For further information about optimizations, please refer to Section 4.5.6, “Short cuts”.

6.2.4. Execution

You can either compile and run the code yourself, or follow the instructions for preparing the examples and use the script helloworld_fractal.sh (or .bat). If you choose the first solution, do not forget to set the gcm.provider system property (or the fractal.provider system property).

If you run the program with no arguments (i.e. not using the parser, no wrapper composite components, and local deployment) , you should get something like this:

  1: --- Fractal Helloworld example ---------------------------------------------
  2: ---
  3: --- The expected result is an exception
  4: ---
  5:
  6: [INFO communication.rmi] Created a new registry on port 6646
  7: [INFO proactive.mop] Generating class :
  8:   pa.stub.org.objectweb.proactive.core.component.type._StubComposite
  9: [INFO proactive.mop] Generating class :
 10:   pa.stub.org.objectweb.proactive.core.jmx.util._StubJMXNotificationListener
 11: [INFO proactive.mop] Generating class :
 12:   pa.stub.org.objectweb.proactive.examples.components.helloworld._StubClientImpl
 13: [INFO proactive.mop] Generating class :
 14:   pa.stub.org.objectweb.proactive.examples.components.helloworld._StubServerImpl

You can see:

  • line 6: the creation of a rmi registry

  • line 7 to 14: the on-the-fly generation of ProActive stubs (the generation of component functional interfaces is silent)

Then you have (the exception that pops out is actually the expected result, and is intended to show the execution path):

  1:Server: print method called
  2:at org.objectweb.proactive.examples.components.helloworld.ServerImpl.print(ServerImpl.java:45)
  3:at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  4:at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  5:at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  6:at java.lang.reflect.Method.invoke(Method.java:597)
  7:at org.objectweb.proactive.core.mop.MethodCall.execute(MethodCall.java:390)
  8:at
  9:  org.objectweb.proactive.core.component.request.ComponentRequestImpl.
 10:    serveInternal(ComponentRequestImpl.java:176)
 11:at org.objectweb.proactive.core.body.request.RequestImpl.serve(RequestImpl.java:170)
 12:at
 13:  org.objectweb.proactive.core.body.BodyImpl$ActiveLocalBodyStrategy.
 14:    serveInternal(BodyImpl.java:539)
 15:at org.objectweb.proactive.core.body.BodyImpl$ActiveLocalBodyStrategy.serve(BodyImpl.java:510)
 16:at org.objectweb.proactive.core.body.AbstractBody.serve(AbstractBody.java:909)
 17:at org.objectweb.proactive.Service.blockingServeOldest(Service.java:175)
 18:at org.objectweb.proactive.Service.blockingServeOldest(Service.java:150)
 19:at org.objectweb.proactive.Service.fifoServing(Service.java:126)
 20:at
 21:  org.objectweb.proactive.core.component.body.ComponentActivity$ComponentFIFORunActive.
 22:    runActivity(ComponentActivity.java:226)
 23:at
 24:  org.objectweb.proactive.core.component.body.ComponentActivity.
 25:    runActivity(ComponentActivity.java:183)
 26:at
 27:  org.objectweb.proactive.core.component.body.ComponentActivity.
 28:    runActivity(ComponentActivity.java:183)
 29:at org.objectweb.proactive.core.body.ActiveBody.run(ActiveBody.java:192)
 30:at java.lang.Thread.run(Thread.java:619)
 31:Server: begin printing...
 32:--------> hello world
 33:Server: print done.c

What can be seen is very different from the output you would get with the Julia implementation. Here is what happens (from bottom to top of the stack):

  • line 30: The active object runs its activity in its own Thread

  • line 20-21-22: The default activity is to serve incoming request in a FIFO order

  • line 8-9-10: Requests (reified method calls) are encapsulated in ComponentRequestImpl objects

  • line 6: A request is served using reflection

  • line 2: The method invoked is the print method of an instance of ServerImpl

Now let us have a look at the distributed deployment: execute the program with the parameters 'distributed parser'. You should get something similar to the following:

  1: --- Fractal Helloworld example ---------------------------------------------
  2: ---
  3: --- The expected result is an exception
  4: ---
  5:
  6: [INFO communication.rmi] Created a new registry on port 6646
  7: [INFO proactive] ************* Reading deployment descriptor:
  8:   file:/home/ProActive/classes/Examples/org/objectweb/proactive/examples/components/
  9:     helloworld/deployment.xml ********************
 10: [INFO proactive.deployment] created VirtualNode name=VN1
 11: [INFO proactive.deployment] created VirtualNode name=VN2
 12: [INFO proactive.deployment] created VirtualNode name=VN3
 13: [INFO proactive.mop] Generating class :
 14:   pa.stub.org.objectweb.proactive.core.jmx.util._StubJMXNotificationListener
 15: [INFO deployment.log]
 16: [INFO deployment.log] 311@saturn.inria.fr -
 17:   [INFO proactive.runtime] **** Starting jvm on 138.96.218.113
 18: [INFO proactive.events] **** Mapping VirtualNode VN1 with Node:
 19:   rmi://138.96.218.113:6646/VN11559562212 done
 20: [INFO proactive.mop] Generating class :
 21:   pa.stub.org.objectweb.proactive.examples.components.helloworld._StubClientImpl
 22: [INFO deployment.log] 311@saturn.inria.fr -
 23:   [INFO communication.rmi] Detected an existing RMI Registry on port 6646
 24: [INFO deployment.log]
 25: [INFO deployment.log] 97714@saturn.inria.fr -
 26:   [INFO proactive.runtime] **** Starting jvm on 138.96.218.113
 27: [INFO proactive.events] **** Mapping VirtualNode VN2 with Node:
 28:   rmi://138.96.218.113:6646/VN2914088183 done
 29: [INFO proactive.mop] Generating class :
 30:   pa.stub.org.objectweb.proactive.examples.components.helloworld._StubServerImpl
 31: [INFO deployment.log] 97714@saturn.inria.fr - [INFO communication.rmi] Detected an existing RMI Registry on port 6646
 32: [INFO proactive.mop] Generating class :
 33:   pa.stub.org.objectweb.proactive.core.component.type._StubComposite

What is new is:

  • line 7-8-9: the parsing of the deployment descriptor

  • line 16-17 and 25-26: the creation of 2 virtual machines on the host 'saturn.inria.fr'

  • line 10-11-12: the creation of virtual nodes VN1, VN2 and VN3

  • line 18-19 and 27-28: the mapping of virtual nodes VN1 and VN2 to the nodes specified in the deployment descriptor

Then, we get the same output as for a local deployment, the activity of active objects is independent from its location.

  1: [INFO deployment.log] Server: print method called
  2: [INFO deployment.log] at
  3:   org.objectweb.proactive.examples.components.helloworld.ServerImpl.print(ServerImpl.java:45)
  4: [INFO deployment.log] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  5: [INFO deployment.log] at
  6:   sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  7: [INFO deployment.log] at
  8:   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  9: [INFO deployment.log] at java.lang.reflect.Method.invoke(Method.java:597)
 10: [INFO deployment.log] at org.objectweb.proactive.core.mop.MethodCall.execute(MethodCall.java:390)
 11: [INFO deployment.log] at
 12:   org.objectweb.proactive.core.component.request.ComponentRequestImpl.
 13:     serveInternal(ComponentRequestImpl.java:176)
 14: [INFO deployment.log] at
 15:   org.objectweb.proactive.core.body.request.RequestImpl.serve(RequestImpl.java:170)
 16: [INFO deployment.log] at
 17:   org.objectweb.proactive.core.body.BodyImpl$ActiveLocalBodyStrategy.
 18:     serveInternal(BodyImpl.java:539)
 19: [INFO deployment.log] at
 20:   org.objectweb.proactive.core.body.BodyImpl$ActiveLocalBodyStrategy.serve(BodyImpl.java:510)
 21: [INFO deployment.log] at
 22:   org.objectweb.proactive.core.body.AbstractBody.serve(AbstractBody.java:909)
 23: [INFO deployment.log] at org.objectweb.proactive.Service.blockingServeOldest(Service.java:175)
 24: [INFO deployment.log] at org.objectweb.proactive.Service.blockingServeOldest(Service.java:150)
 25: [INFO deployment.log] at org.objectweb.proactive.Service.fifoServing(Service.java:126)
 26: [INFO deployment.log] at
 27:   org.objectweb.proactive.core.component.body.ComponentActivity$ComponentFIFORunActive.
 28:     runActivity(ComponentActivity.java:226)
 29: [INFO deployment.log] at
 30:   org.objectweb.proactive.core.component.body.ComponentActivity.
 31:     runActivity(ComponentActivity.java:183)
 32: [INFO deployment.log] at
 33:   org.objectweb.proactive.core.component.body.ComponentActivity.
 34:     runActivity(ComponentActivity.java:183)
 35: [INFO deployment.log] at org.objectweb.proactive.core.body.ActiveBody.run(ActiveBody.java:192)
 36: [INFO deployment.log] at java.lang.Thread.run(Thread.java:619)
 37: [INFO deployment.log] Server: begin printing...
 38: [INFO deployment.log] ->hello world
 39: [INFO deployment.log] Server: print done.
 40:---------------------------------------------------------

6.2.5. The HelloWorld ADL files

org.objectweb.proactive.examples.components.helloworld.helloworld-distributed-wrappers:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN" "classpath://org/objectweb/proactive/core/component/adl/xml/proactive.dtd">

<definition name="org.objectweb.proactive.examples.components.helloworld.helloworld-distributed-wrappers">
    <interface name="r" role="server" signature="java.lang.Runnable"/>
    <!-- @snippet-start exported_virtual_node_1 -->
    <exportedVirtualNodes>
        <exportedVirtualNode name="VN1">
            <composedFrom>
                <composingVirtualNode component="client" name="client-node"/>
            </composedFrom>
        </exportedVirtualNode>
        <exportedVirtualNode name="VN2">
            <composedFrom>
                <composingVirtualNode component="server" name="server-node"/>
            </composedFrom>
        </exportedVirtualNode>
    </exportedVirtualNodes>
    <!-- @snippet-end exported_virtual_node_1 -->
  <component name="client-wrapper" definition="org.objectweb.proactive.examples.components.helloworld.ClientType">
      <component name="client" definition="org.objectweb.proactive.examples.components.helloworld.ClientImpl"/>
      <binding client="this.r" server="client.r"/>
      <binding client="client.s" server="this.s"/>
      <controller desc="composite"/>
  </component>
  <component name="server-wrapper" definition="org.objectweb.proactive.examples.components.helloworld.ServerType">      
      <component name="server" definition="org.objectweb.proactive.examples.components.helloworld.ServerImpl"/>
      <binding client="this.s" server="server.s"/>
      <controller desc="composite"/>
  </component>
  <binding client="this.r" server="client-wrapper.r"/>
  <binding client="client-wrapper.s" server="server-wrapper.s"/>
</definition>

org.objectweb.proactive.examples.components.helloworld.ClientType:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN" "classpath://org/objectweb/proactive/core/component/adl/xml/proactive.dtd">

<definition name="org.objectweb.proactive.examples.components.helloworld.ClientType" extends="org.objectweb.proactive.examples.components.helloworld.RootType">
    <interface name="r" role="server" signature="java.lang.Runnable"/>
    <interface name="s" role="client" signature="org.objectweb.proactive.examples.components.helloworld.Service"/>
</definition>

org.objectweb.proactive.examples.components.helloworld.ClientImpl:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN" "classpath://org/objectweb/proactive/core/component/adl/xml/proactive.dtd">

<definition name="org.objectweb.proactive.examples.components.helloworld.ClientImpl" extends="org.objectweb.proactive.examples.components.helloworld.ClientType">
    <!-- @snippet-start exported_virtual_node_2 -->
    <exportedVirtualNodes>
        <exportedVirtualNode name="client-node">
            <composedFrom>
                <composingVirtualNode component="this" name="client-node"/>
            </composedFrom>
        </exportedVirtualNode>
    </exportedVirtualNodes>
    <!-- @snippet-break exported_virtual_node_2 -->
    <content class="org.objectweb.proactive.examples.components.helloworld.ClientImpl"/>
    <!-- @snippet-resume exported_virtual_node_2 -->
    <virtual-node name="client-node"/>
    <!-- @snippet-end exported_virtual_node_2 -->
</definition>

org.objectweb.proactive.examples.components.helloworld.ServerType:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN" "classpath://org/objectweb/proactive/core/component/adl/xml/proactive.dtd">

<definition name="org.objectweb.proactive.examples.components.helloworld.ServerType">
  <interface name="s" role="server" signature="org.objectweb.proactive.examples.components.helloworld.Service"/>
</definition>

org.objectweb.proactive.examples.components.helloworld.ServerImpl:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN" "classpath://org/objectweb/proactive/core/component/adl/xml/proactive.dtd">

<definition name="org.objectweb.proactive.examples.components.helloworld.ServerImpl" extends="org.objectweb.proactive.examples.components.helloworld.ServerType">
    <exportedVirtualNodes>
        <exportedVirtualNode name="server-node">
            <composedFrom>
                <composingVirtualNode component="this" name="server-node"/>
            </composedFrom>
        </exportedVirtualNode>
    </exportedVirtualNodes>
  <content class="org.objectweb.proactive.examples.components.helloworld.ServerImpl"/>
  <attributes signature="org.objectweb.proactive.examples.components.helloworld.ServiceAttributes">
    <attribute name="header" value="->"/>
    <attribute name="count" value="1"/>
  </attributes>
  <controller desc="primitive"/>
  <virtual-node name="server-node"/>
</definition>