• Documentation
 
Fractal Tutorial : Simple HelloWorld

Fractal Tutorial : Simple HelloWorld


Chapter 1. Introduction

This tutorial explains how to program a Fractal component-based application in Java, and how to deploy it. This tutorial is independent of any specific Java implementation of the Fractal component model, provided it is compliant with the 3.3 conformance level (cf. the Fractal specification).

The example used throughout this tutorial is a very simple application made of two primitive components inside a composite component (see the figure below). The first primitive component is a "server" component that provides an interface to print messages on the console. It can be parameterized with a "header" attribute to configure the header printed in front of each message. The other primitive component is a "client" component that uses the previous component to print some messages.

The server component provides a server interface named "s" of type Service, which provides a print method. It also has an attribute controller interface of type ServiceAttributes, which provides two methods to get and set the attribute of the server component.

The client component provides a server interface named "r" of type java.lang.Runnable, which provides a run method, called when the application is launched. It also has a client interface named "s" of type Service.

Chapter 2. Implementation

The application can be programmed in two steps, by creating the component interfaces first, and then implementing these interfaces in the component classes.

2.1. Creating the component interfaces

Three interfaces must be implemented: the two "functional" interfaces Service and java.lang.Runnable, and the attribute controller interface ServiceAttributes.

The functional interfaces are programmed "normally", i.e., the Fractal model does not impose any constraints on the Fractal functional component interfaces, except the fact that they must be public. The Service and java.lang.Runnable interfaces are therefore very simple to implement :


package helloworld;

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

Fractal implementation can automatically create the code of some controllers, some others need that the user writes a basic implementation of these controllers that will be completed automatically by the fractal implementation.

It is the case for the attribute controller. The implementation can't know the java attributes that must be mapped to Fractal attributes. To do so a attribute controller interface that extends the AttributeController interface must be provided, and it must only have getter and setter method pairs. The ServiceAttributes interface is therefore the following:


package helloworld;

import org.objectweb.fractal.api.control.AttributeController;

public interface ServiceAttributes extends AttributeController {
  String getHeader ();
  void setHeader (String header);
}

2.2. Implementing the component classes

The component classes must implement the previous interfaces, and some Fractal control interfaces.

The server component class, called ServerImpl, must implement the Service and ServiceAttributes interfaces. Since the server component does not have client interfaces, the ServerImpl class does not need to implement the BindingController interface. The ServerImpl class is therefore the following:


package helloworld;

public class ServerImpl implements helloworld.Service, helloworld.ServiceAttributes {
  private String header;
  
  public ServerImpl () {
	System.err.println("SERVER created");
  }
  
  public void print (String msg) {
    System.out.println(header + msg);
  }
  
  public String getHeader () {
    return header;
  }

  public void setHeader (final String header) {
    this.header = header;
  }
}

The client component class, called ClientImpl, must implement the java.lang.Runnable interface. Since the client component has client interfaces, ClientImpl must also implement the BindingController interface.The ClientImpl class is therefore the following:


package helloworld;

import org.objectweb.fractal.api.control.BindingController;

public class ClientImpl implements java.lang.Runnable, BindingController {

  private Service service;

  public ClientImpl () {
		System.err.println("CLIENT created");
	}
  
  public void run () {
    service.print("Hello world !");
  }

  public String[] listFc () {
    return new String[] { "s" };
  }

  public Object lookupFc (final String cItf) {
    if (cItf.equals("s")) {
      return service;
    }
    return null;
  }

  public void bindFc (final String cItf, final Object sItf) {
    if (cItf.equals("s")) {
      service = (Service)sItf;
    }
  }

  public void unbindFc (final String cItf) {
    if (cItf.equals("s")) {
      service = null;
    }
  }
}

Chapter 3. Deployment

3.1. Creating the component types

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 = Fractal.getTypeFactory(boot);

We can then create the type of the composite component, which only provides a java.lang.Runnable server interface named "r":


// type of the root component
ComponentType rType = tf.createFcType(new InterfaceType[] {
	tf.createFcItfType("r", "java.lang.Runnable", false, false, false)
});

The type of the client and server components are created in a similar way:


ComponentType cType = tf.createFcType(new InterfaceType[] {
	tf.createFcItfType("r", "java.lang.Runnable", false, false, false),
	tf.createFcItfType("s", "helloworld.Service", true, false, false)
});

ComponentType sType = tf.createFcType(new InterfaceType[] {
	tf.createFcItfType("s", "helloworld.Service", false, false, false),
	tf.createFcItfType("attribute-controller", "helloworld.ServiceAttributes", false, false, false),
});

3.2. Creating the component instances

We could now create the components directly. In order to do this, we first get the GenericFactory interface provided by the bootstrap component:


GenericFactory cf = Fractal.getGenericFactory(boot);

We then create a composite component to instantiate the composite component. Here the "composite" is supposed to describe a component with the LifeCycleController, BindingController and ContentController interfaces.


Component rComp = cf.newFcInstance(rType, "composite", null);

We then create a primitive component to instanciate the client component. Here the "primitive" argument is supposed to describe a component with the LifeCycleController and BindingController interfaces. The "ClientImpl" argument is of course the name of the client component class.


Component cComp = cf.newFcInstance(cType, "primitive", "helloworld.ClientImpl");

We do the same thing for the server component.


Component sComp = cf.newFcInstance(sType, "primitive", "helloworld.ServerImpl");

We can then configure the attributes of the server component.


ServiceAttributes sa = (ServiceAttributes)sComp.getFcInterface("attribute-controller");
sa.setHeader("->");

At this stage we have the following architecture:

We now have to put the client and the server components in the composite component.


Fractal.getContentController(rComp).addFcSubComponent(cComp);
Fractal.getContentController(rComp).addFcSubComponent(sComp);

We then bind the internal client interface "r" of the composite to the server interface "r" of the client.


Fractal.getBindingController(rComp).bindFc("r", cComp.getFcInterface("r"));

Finally, we bind the client interface "s" of the client to the server interface "s" of the server.


Fractal.getBindingController(cComp).bindFc("s", sComp.getFcInterface("s"));

The final architecture is the following:

3.3. Instantiating and launching the application

Likewise, all the application components can be started automatically by just calling the startFc method on the root application component:


Fractal.getLifeCycleController(rComp).startFc();

We can finally (!) call the run method to print the 'helloworld!' message :


((java.lang.Runnable)rComp.getFcInterface("r")).run();

3.4. Increase Fractal application development

The main drawbacks of the pure Java approach are that the software architecture is described at the code level (so you have to compile each time you modify the architecture) and that the user has to implement the non-functional properties of the control interfaces.

To solve these problems there is two tools: Fraclet and Fractal ADL.

  • Fraclet provides a set of Java annotations. The user annotates its business, and Fraclet generates the implementation of the control interfaces.
  • Fractal ADL allow to describe Fractal architecture in xml files. It provides a launcher which can build on-fly the software from its Fractal ADL description.

 
1999-2009 © OW2 Consortium  | Last Published: 2009-02-03 18:28  | Version: 1.1.2-SNAPSHOT