Chapter 33. Component examples

Three examples are presented: code snippets for visualizing the transition between active objects and components, the 'hello world', from the Fractal tutorial, and C3D component version. The programming model is Fractal, and one should refer to the Fractal documentation for other detailed examples.

33.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 foo(); // dummy method
} 

'AImpl' is the class implementing this interface:

public class AImpl implements A {
 public AImpl() {}
 public String foo() {
 // do something
 }
}  

The class is then instantiated in a standard way:

 A object = new AImpl(); 

Active objects are instantiated using factory methods from the ProActive class (see Section 13.10, “The Hello world example”). 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 active_object = (A)ProActive.newActive(
 AImpl, // 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 controller.

33.1.1. Type

The type of the 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 components of the application. In order to do this, we must first 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 fractal.provider system property, and uses this instance to get the bootstrap component):

 Component boot = Fractal.getBootstrapComponent(); 

We then get the TypeFactory interface provided by this bootstrap component:

 TypeFactory tf = (TypeFactory)boot.getFcInterface('type-factory'); 

We can then 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)
}); 

33.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, // signature of the base class
 new Object[] {}, // Object[]
 aNode // location, could also be a virtual node
); 

33.1.3. Description of the controller

Properties relative to the controller 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, COMPOSITE, or PARALLEL
); 

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

Component component = componentFactory.newFcInstance(
 componentType, // type of the component (defining the client and server interfaces)
 controllerDesc, // implementation-specific description for the controller
 contentDesc // implementation-specific description for the content
); 

33.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:

        
       

And the AImpl class is:

// The modified AImpl class
public class AImpl implements A, BindingController {
 Service service; // attribute corresponding to a client interface
 public AImpl() {}
 // implementation of the A interface
 public String foo() {
   return service.bar(); // 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;
   }
 }
} 

33.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.

33.2.1. Set-up

You can find the code for this example in the package org.objectweb.proactive.examples.components.helloworld of 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 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).

  • Collective interfaces could be implemented the same way than suggested, but using the Fractive.createCollectiveClientInterface method will prove useful with this implementation: you are then able to use the functionalities provided by the typed groups API.

  • Components can be distributed

  • the ClientImpl provides an empty no-args constructor.

33.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). The goal was initially to show the interception shortcut mechanism in Julia. In the current ProActive implementation, there are no such shortcuts, as the different components can be distributed, and all invocations are intercepted. The exercise is still of interest, as it involves composite components.

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

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

33.2.3. Distributed deployment

This section is specific to the ProActive 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 21, XML Deployment Descriptors).

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 33.2. Without wrappers, the primitive components are distributed.

With wrappers, where again, only the primitive components are distributed.

Figure 33.3. With wrappers, where again, only the primitive components are distributed.

Currently, 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. We are currently working on optimizations that would 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. It could imply compromises between dynamicity and performance issues.

33.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 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:

01 --> This ClassFileServer is reading resources from classpath
02 Jini enabled
03 Ibis enabled
04 Created a new registry on port 1099
05 //crusoe.inria.fr/Node363257273 successfully bound in registry at //crusoe.inria.fr/Node363257273
06 Generating class: pa.stub.org.objectweb.proactive.core.component.type.Stub_Composite
07 Generating class: pa.stub.org.objectweb.proactive.examples.components.helloworld.Stub_ClientImpl
08 Generating class: pa.stub.org.objectweb.proactive.examples.components.helloworld.Stub_ServerImpl 

You can see:

  • line 01: the creation of the class file server which handles the on-the-fly generation and distribution of ProActive stubs and component functional interfaces

  • line 04: the creation of a rmi registry

  • line 05: the registration of the default runtime node

  • line 06 to 08: 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):

01 Server: print method called
02 at org.objectweb.proactive.examples.components.helloworld.ServerImpl.print(ServerImpl.java:37)
03 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
04 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
05 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
06 at java.lang.reflect.Method.invoke(Method.java:324)
07 at org.objectweb.proactive.core.mop.MethodCall.execute(MethodCall.java:373)
08 at org.objectweb.proactive.core.component.request.ComponentRequestImpl.serveInternal(ComponentRequestImpl.java:163)
09 at org.objectweb.proactive.core.body.request.RequestImpl.serve(RequestImpl.java:108)
10 at org.objectweb.proactive.core.body.BodyImpl$ActiveLocalBodyStrategy.serve(BodyImpl.java:297)
11 at org.objectweb.proactive.core.body.AbstractBody.serve(AbstractBody.java:799)
12 at org.objectweb.proactive.core.body.ActiveBody$FIFORunActive.runActivity(ActiveBody.java:230)
13 at org.objectweb.proactive.core.body.ActiveBody.run(ActiveBody.java:145)
14 at java.lang.Thread.run(Thread.java:534)
15 Server: begin printing...
16 --------> hello world
17 Server: print done.

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 14: The active object runs its activity in its own Thread

  • line 12: The default activity is to serve incoming request in a FIFO order

  • line 08: Requests (reified method calls) are encapsulated in ComponentRequestImpl objects

  • line 06: A request is served using reflection

  • line 02: 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:

01 --> This ClassFileServer is reading resources from classpath
02 Jini enabled
03 Ibis enabled
04 Created a new registry on port 1099
05 ************* Reading deployment descriptor: file:/0/user/mmorel/ProActive/classes/org/objectweb/proactive/examplescomponents/helloworld/deployment\
.xml ********************
06 created VirtualNode name=VN1
07 created VirtualNode name=VN2
08 created VirtualNode name=VN3
09 **** Starting jvm on crusoe.inria.fr
10 --> This ClassFileServer is reading resources from classpath
11 Jini enabled
12 Ibis enabled
13 Detected an existing RMI Registry on port 1099
14 //crusoe.inria.fr/VN1462549848 successfully bound in registry at //crusoe.inria.fr/VN1462549848
15 **** Mapping VirtualNode VN1 with Node: //crusoe.inria.fr/VN1462549848 done
16 Generating class: pa.stub.org.objectweb.proactive.examples.components.helloworld.Stub_ClientImpl
17 **** Starting jvm on crusoe.inria.fr
18 --> This ClassFileServer is reading resources from classpath
19 Jini enabled
20 Ibis enabled
21 Detected an existing RMI Registry on port 1099
22 //crusoe.inria.fr/VN21334775605 successfully bound in registry at //crusoe.inria.fr/VN21334775605
23 **** Mapping VirtualNode VN2 with Node: //crusoe.inria.fr/VN21334775605 done
24 Generating class: pa.stub.org.objectweb.proactive.examples.components.helloworld.Stub_ServerImpl
25 //crusoe.inria.fr/Node1145479146 successfully bound in registry at //crusoe.inria.fr/Node1145479146
26 Generating class: pa.stub.org.objectweb.proactive.core.component.type.Stub_Composite
27 MOPClassLoader: class not found, trying to generate it
28 ClassServer sent class Generated_java_lang_Runnable_r_representative successfully
39 MOPClassLoader: class not found, trying to generate it
30 ClassServer sent class Generated_java_lang_Runnable_r_representative successfully
31 MOPClassLoader: class not found, trying to generate it
32 ClassServer sent class Generated_org_objectweb_proactive_examples_components_helloworld_Service_s_representative successfully
33 MOPClassLoader: class not found, trying to generate it
34 ClassServer sent class Generated_org_objectweb_proactive_examples_components_helloworld_ServiceAttributes_attribute_controller_representative succe\
ssfully
35 ClassServer sent class pa.stub.org.objectweb.proactive.examples.components.helloworld.Stub_ServerImpl successfully

What is new is:

  • line 05 the parsing of the deployment descriptor

  • line 09 and 17: the creation of 2 virtual machines on the host 'crusoe.inria.fr'

  • line 15 and 24: the mapping of virtual nodes VN1 and VN2 to the nodes specified in the deployment descriptor

  • line 35: the dynamic downloading of the stub class for ServerImpl: the stub class loader does not find the classes of the stubs in the current VM, and fetches the classes from the ClassServer

  • line 28, 30, 32, 34: the dynamic downloading of the classes corresponding to the components functional interfaces (they were silently generated)

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

01 Server: print method called
02 at org.objectweb.proactive.examples.components.helloworld.ServerImpl.print(ServerImpl.java:37)
03 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
04 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
05 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
06 at java.lang.reflect.Method.invoke(Method.java:324)
07 at org.objectweb.proactive.core.mop.MethodCall.execute(MethodCall.java:373)
08 at org.objectweb.proactive.core.component.request.ComponentRequestImpl.serveInternal(ComponentRequestImpl.java:163)
09 at org.objectweb.proactive.core.body.request.RequestImpl.serve(RequestImpl.java:108)
10 at org.objectweb.proactive.core.body.BodyImpl$ActiveLocalBodyStrategy.serve(BodyImpl.java:297)
11 at org.objectweb.proactive.core.body.AbstractBody.serve(AbstractBody.java:799)
12 at org.objectweb.proactive.core.body.ActiveBody$FIFORunActive.runActivity(ActiveBody.java:230)
13 at org.objectweb.proactive.core.body.ActiveBody.run(ActiveBody.java:145)
14 at java.lang.Thread.run(Thread.java:534)
15 Server: begin printing...
16 ->hello world
17 Server: print done.

33.2.5. The HelloWorld ADL files

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

       <?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"/>
  <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>
  <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.fractal

       <?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.fractal

       <?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">
  <exportedVirtualNodes>
      <exportedVirtualNode name="client-node">
        <composedFrom>
            <composingVirtualNode component="this" name="client-node"/>
        </composedFrom>
      </exportedVirtualNode>
    </exportedVirtualNodes>
    <content class="org.objectweb.proactive.examples.components.helloworld.ClientImpl"/>
    <virtual-node name="client-node" cardinality="single"/>
</definition>

      

org.objectweb.proactive.examples.components.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" cardinality="single"/>
</definition>

      

33.3. The Comanche example

The Comanche example is a nice introduction to component based development with Fractal. It explains how to design applications using components, and how to implement these applications using the Fractal API.

You will notice that the example presented in this tutorial is based on Comanche, a simplistic http server. However, this example extensively uses reference passing through components. For example Request objects are passed by reference. This is incompatible with the ProActive programming model, where, to avoid shared passive objects, all passive objects passed to active objects are actually passed by copy (see Chapter 12, ProActive Basis, Active Object Definition). As active objects are themselves passed by reference, one could argue that we could turn some passive object into active objects. This would allow remote referencing through stubs. Unfortunately, for reasons specific to the Sockets and Streams implementations, (Socket streams implementations do not provide empty no-arg constructors), it is not easily possible to encapsulate some of the needed resource classes into active objects.

33.4. The C3D component example

There is a complete example of migrative Active Object code to Component code. This can be seen in the Guided Tour: Chapter 10, C3D - from Active Objects to Components.