Fractal - Fraclet - User Guide

About this document

  • Title: User Guide
  • Author: Romain Rouvoy (University of Lille 1)
  • Version: 3.2.2 (fraclet-java)
  • Released: March 19th, 2009

Table of Contents

  1. Overview of Spoon
  2. Annotation Description
  3. Spoon/Maven2 Configuration
  4. Revisiting the HelloWorld Example

About Spoon

Spoon is a Java 5 open compiler built on javac. It uses compile-time reflection to specify program analysis and transformations. Spoon provides the user with a representation of the Java AST called a meta-model, which allows both for reading and writing. Each interface of the meta-model is a compile-time program element (CtElement), which represents an AST node. Using this meta-model and a specific API, Spoon allows the programmer to process Java 5 programs. This processing is implemented with a visitor pattern that scans each visited program element and can apply some user-defined processing jobs called processors. In particular, the processing can be annotation-driven, in a similar way to XDoclet, but using Java 5 annotations. In that case, programmers define so-called annotation processors. Once the program's model has been processed, a processor pretty prints the Java program, which is usually compiled again to generate the processed program's class files.

In addition, Spoon provides templates in pure Java, which are Java class that contains template parameters, which are defined as fields annotated with @Parameter. Template parameters can represent primitive values (such as literal values, program element's names, types), or actual CtElements (ASTs). In the template code, all the references to template parameters can be substituted by their actual values using the substitution engine API provided by Spoon. The templates are useful to express patterns that can be used for generating code, as exampled by Generative Programming.

To implement Fraclet with have developed a set of Spoon processors and templates to process our annotations. This tutorial does not detail the implementation of the processors and templates but focus on the use of Fraclet annotations.

Available Annotations

A small set of annotations have been defined for easy programming of Fractal components. The table below summarises these annotations.

AnnotationLocationDescription
@ComponentClassAnnotation to describe a component.
@InterfaceInterfaceAnnotation to describe a server interface.
@DefinitionClassAnnotation to include a custom Fractal ADL definition.
@AttributeFieldAnnotation to describe an component attribute.
@RequiresFieldAnnotation to describe a client interface.
@LifecycleMethodAnnotation to handle a step of the component life cycle.
@ControllerFieldAnnotation to access the controller part of the component.

In addition to this small annotations set, additional annotations are also available for handling advanced concepts of Fractal.

AnnotationLocationDescription
@DataClassAnnotation to describe a data exchanged between components.
@MembraneClassAnnotation to describe the controller part of the component.
@NodeClassAnnotation to define the node hosting the component.

Core Annotations

@Component

Details:
This class annotation describes a component and is used to generate the associated Fractal ADL definition. This annotation is mandatory for any definition of a component (abstract or concrete).

Parameters:

ParameterTypeDescriptionContingency
nameStringname of the associated Fractal description.Optional
provides@Interface[]explicit list of server interfaces.Optional
uses@Definition[]explicit list of custom architecture descriptions.Optional

PS. The attribute provides is used when the server interfaces implemented by the component are not using the @Interface annotation (e.g., the interface java.lang.Runnable).

Examples:

@Component
public class MyComponent implements Runnable { 
    (...)
}

Generate the following Fractal ADL definition:
  <definition name="MyComponent">
    (...)               
    <content class="MyComponent"/>  
  </definition>
@Component(name="MyComponentDefinition")
public class MyComponent implements Runnable {
    (...)
}

Generate the following Fractal ADL definition:
  <definition name="MyComponentDefinition">
    (...)               
    <content class="MyComponent"/>  
  </definition>
@Component(name="MyComponentDefinition", provides=@Interface(name="r", signature=Runnable.class))
public class MyComponent implements Runnable {
    (...)
}

Generate the following Fractal ADL definition:
  <definition name="MyComponentDefinition">
    <interface name="r" role="server" cardinality="singleton" contingency="mandatory" signature="java.lang.Runnable"/>  
    (...)                
    <content class="MyComponent"/>    
  </definition>
@Component(name="MyComponentDefinition", uses=@Definition(name="RunnableComponent"))
public class MyComponent implements Runnable {
    (...)
}

Generate the following Fractal ADL definition:
  <definition name="MyComponentDefinition" extends="RunnableComponent">
    (...)                
    <content class="MyComponent"/>    
  </definition>

@Interface

Details:
This interface annotation is used to describe a server interface provided by a component. Once tagged with this annotation, the interface will automatically be recognized as a server interface for the components implementing this interface. Furthermore, a Fractal ADL (abstract) definition will be generated for this interface.

Parameters:

ParameterTypeDescriptionContingency
nameStringname of the server interface.Optional
(default value is the Class name)
signatureClass<?>signature of the server interface.Optional
(default value is the Class signature)

Examples:

@Interface
public interface Service { 
    (...)
}

Generate the following Fractal ADL abstract definition:
  <definition name="Service">
    <interface name="service" signature="Service" role="server" cardinality="singleton" contingency="mandatory"/>
  </definition>
@Interface(name="s")
public interface Service { 
    (...)
}

Generate the following Fractal ADL abstract definition:
  <definition name="Service">
    <interface name="s" signature="Service" role="server" cardinality="singleton" contingency="mandatory"/>
  </definition>
@Interface(name="s")
public interface Service {
    (...)
}
@Component
public class Server implements Service {
    (...)
}                        

Generate the following Fractal ADL definitions:
  <definition name="Service">
    <interface name="service" signature="Service" role="server" cardinality="singleton" contingency="mandatory"/>
  </definition>            

  <definition name="Server" extends="Service">
    (...)
    <content class="Server"/>
  </definition>

@Definition

Details:
This class annotation describes a custom definitions that need to be supported by the component definition.

Parameters:

ParameterTypeDescriptionContingency
nameStringdefinitions to integrate.Mandatory
argumentsStringlist of arguments to apply to the definition.
(default values can be defined as argument=>value)
Optional

Examples:

@Component(uses=@Definition(name="MyDefinition",argument="runnableItf=>r"))
public class Client implements Runnable {
    (...)
}

Generates the following Fractal ADL definition:
  <definition name="Client" argument="runnableItf=r" extends="MyDefinition(runnableItf)">
    (...)
  </definition>

@Attribute

Details:
This field annotation describes an attribute supported by a component. Fields marked with this annotation will automatically be handled by the attribute controller of the component.

Parameters:

ParameterTypeDescriptionContingency
nameStringname of the argument used to configure the attribute.Optional
(default value is the field name)
modeAccessaccess mode for the attribute.
(values are Access.READ_WRITE | Access.READ_ONLY | Access.WRITE_ONLY).
Optional
(default value is Access.READ_WRITE)
valueStringdefault value of the attribute.Optional
(attribute is defined as mandatory if no value is defined)
getStringsignature of a custom attribute getter.Optional
(getter is automatically generated if empty)
setStringsignature of a custom attribute setter.Optional
(setter is automatically generated if empty)

Example:

@Component
public class Server implements Service {
    @Attribute(mode=Access.READ_ONLY)
    private int constantValue = 10 ;
    @Attribute(value=">>") 
    private String header ;
    @Attribute(name="msg", set="setMessage", mode=Access.WRITE_ONLY)
    private String message ;
    (...)
    private void setMessage(String m) {
        System.out.println("Calling my custom attribute setter");
        this.message = m;
    }
}        

Generates the following Fractal ADL definitions:
  <definition name="Server" arguments="msg,header=>>">
    <interface name="service" signature="Service" role="server" cardinality="singleton" contingency="mandatory"/>
    <content class="Server"/>
    <attributes signature="ServerAttributes">
      <attribute name="message" value="${msg}"/>
      <attribute name="header" value="${header}"/>
    </attributes>
  </definition>

@Requires

Details:
This field annotation describes a client interface.

Parameters:

ParameterTypeDescriptionContingency
nameStringname of the client interface.Optional
cardinalityCardinalitycardinality of the client interface.
(values are Cardinality.SINGLETON | Cardinality.COLLECTION)
Optional
(default value is Cardinality.SINGLETON)
contingencyContingencycontingency of the client interface.
(values are Contingency.MANDATORY | Contingency.OPTIONAL)
Optional
(default value is Contingency.MANDATORY)
bindStringsignature of a custom interface binder.Optional
(assignment is automatically done if empty)
unbindStringsignature of a custom interface unbinder.Optional
(unassignment is automatically done if empty)

Example:

@Component
public class Client implements Runnable {
    @Requires(name = "default", bind="setDefault")
    private Service defaut;
    @Requires(cardinality = Cardinality.COLLECTION)
    private Map<String,Service> service = new HashMap<String,Service>();
    (...)
    private void setDefault(Service d) {
        System.out.println("Calling my custom attribute setter");
        this.defaut = d;
    }
}

Generates the following Fractal ADL definitions:
  <definition name="Client">
    <interface name="default" signature="Service" role="client" cardinality="singleton" contingency="mandatory"/>
    <interface name="service" signature="Service" role="client" cardinality="collection" contingency="mandatory"/>
    <content class="Client"/>
  </definition>

@Lifecycle

Details:
This method annotation provides a way to define a lifecycle handler supported by the controller part of the associated Fractal component.

Parameters:

ParameterTypeDescriptionContingency
stepSteplife-cyle step to listen.
(values are Step.CREATE | Step.START | Step.STOP | Step.DESTROY).
Required
policyPolicystep handling policy.
(values are Policy.SYNCHRONOUS | Policy.ASYNCHRONOUS).
Optional
(default value is Policy.SYNCHRONOUS)

Example:

@Component
public class Client implements Runnable {
    @LifeCycle(step=Step.START, policy=Policy.ASYNCHRONOUS)
    private void setup() {
        System.out.println("Starting the component Client asynchronously...");
    }
    @LifeCycle(step=Step.STOP)
    private void tearDown() {
        System.out.println("Stopping the component Client synchronously...");
    }
    (...)
}

@Controller

Details:

This class annotation provides access to the controllers supported by the component.

Parameters:

ParameterTypeDescriptionContingency
valueStringThe name of the controller.
(possible values are name-controller | super-controller | binding-controller | attribute-controller | lifecycle-controller | component | any other controller)
Optional (default value is component)

Examples:

@Component
public class Client implements Runnable {
    @Controller
    private org.objectweb.fractal.api.Component comp; 
    (...)
}
@Component
public class Client implements Runnable {
    @Controller("name-controller")
    private NameController nc; 
    @Controller("super-controller")
    private SuperController sc; 
    (...)
}

Additional Annotations

@Data

Details:
This class annotation describes data exchanged between components (via their client/server interfaces).

Example:

@Data
public class Message { 
    (...)
}

@Membrane

Details:
This class annotation describes the controller part of the component.

Parameters:

ParameterTypeDescriptionContingency
controllerStringIdentifier of the component controller.Mandatory
templateStringIdentifier of the template controller.Mandatory

Example:

@Component
@Membrane(controller="myPrimitive")
public class Client implements Runnable {
    (...)
}

Generates the following Fractal ADL definition:
  <definition name="Client">
    (...)
    <controller desc="MyPrimitive"/>
  </definition>
@Component
@Membrane(template="myTemplate")
public class Client implements Runnable {
    (...)
}

Generates the following Fractal ADL definition:
  <definition name="Client">
    (...)
    <template-controller desc="MyTemplate"/>
  </definition>

@Node

Details:
This class annotation describes the name of the node hosting the component instance for a distributed deployment (using Fractal RMI).

Parameters:

ParameterTypeDescriptionContingency
valueStringName of the hosting node.Mandatory

Example:

@Component
@Node("clientNode")
public class Client implements Runnable {
    (...)
}

Generates the following Fractal ADL definition:
  <definition name="Client" extends="MyDefinition">
    (...)
    <virtual-node name="clientNode">
  </definition>

Configuration

Spoon Configuration

You should first describe the list of spoonlets that need to be applied to your source code. Fraclet basically provides two spoonlets for introducing the Fractal API callbacks and generating the Fractal ADL definitions, respectively. To do so, you should create a file named spoon.cfg.xml at the root of your project containing the following definition:

<?xml version="1.0" encoding="UTF-8"?>
<spoon>
  <spoonlet groupId="org.objectweb.fractal.fraclet.java" artifactId="fractal-spoonlet" version="3.2" />
  <spoonlet groupId="org.objectweb.fractal.fraclet.java" artifactId="fractaladl-spoonlet" version="3.2" />
</spoon>

Maven2 Configuration

Then, you should describe the list of spoonlets as Maven2 artefact dependencies.

<project>
  (...)
  <dependencies>
    (...)
    <dependency>
      <groupId>org.objectweb.fractal.fraclet.java</groupId>
      <artifactId>fractal-spoonlet</artifactId>
      <version>3.2</version>
    </dependency>
    <dependency>
      <groupId>org.objectweb.fractal.fraclet.java</groupId>
      <artifactId>fractaladl-spoonlet</artifactId>
      <version>3.2</version>
    </dependency>
  </dependencies>
  (...)
<project>

Finally, you should extend the Maven2 build process by using the Spoon Maven2 plugin.

<project>
  (...)
  <build>
    <plugins>
      <plugin>
        <groupId>net.sf.alchim</groupId>
        <artifactId>spoon-maven-plugin</artifactId>
        <version>0.7.1</version>
        <executions>
          <execution>
            <goals>
              <goal>recompile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  (...)
<project>

Revisiting HelloWorld

This section provides a quick overview of the benefits of Fraclet. In particular, it illustrates that, using annotations, component source code becomes more concise and easier to maintain. Moreover, using Fraclet, more than 60% of the source code (Java, FractalADL) can be saved.

HelloWorld Architecture Overview

The figure below introduces the well-known HelloWorld example implemented with Fractal components.

HelloWorld Components Implementation

The source code below represents the Java code and the Fraclet annotations written to implement the Client and the Server Fractal components:

@Component(provides=@Interface(name="r",signature=Runnable.class))
public class Client implements Runnable {
  @Requires(name = "s")
  private Service defaut;
  @Attribute(value="Hello !")
  protected String message;
            
  public void run() {
    this.defaut.print(this.message);
} }

The Client class defines the Runnable interface as a Fractal interface using the @Interface annotation. The field defaut is annoted as a client interface (using @Requires), and will be named "s". The attribute message is annoted as a Fractal attribute (using @Attribute), which will be automatically initialized to "Hello !".

@Interface(name="s")
public interface Service {
  void print(String message);
}

The Service interface is marked with @Interface to define the name of the Fractal interface as "s".

@Component                              
public class Server implements Service {
  @Attribute private String header;
  @Attribute private int counter;
                
  public void print(final String message) {
    for (int i = 0; i < this.counter; i++)
      System.out.println(this.header + message);
} }

The Server class inherits automatically from the Service annotations. The header and the counter attributes are defined as Fractal attributes (using @Attribute), whose initial value will be defined when the component will be created.

HelloWorld Architecture Definition

The assembly definition below represents the FractalADL assembly defined to describe the HelloWorld Fractal component:

<definition name="HelloWorld" extends="ClientComposite(s=>server)">
  <component name="server" definition="Server('>>',2)"/>
</definition>

This definition creates a composite component HelloWorld. Then it specifies that the definition of the component named server is Server and that the values of the header and the counter attributes are '>>' and 2, respectively.

Directory Structure

The directory structure below presents the list of compiled, generated and written files when using Fraclet to implement the HelloWorld example:

%example%
  * src/main/java
    - Client.java
    - Server.java
    - Service.java
  * src/main/resources
    - HelloWorld.fractal
  * target/generated-sources/spoon
    - Client.java
    - ClientAttributes.java
    - Server.java
    - ServerAttributes.java
    - Service.java
  * target/classes
    - Client.class
    - Client.fractal
    - ClientAttributes.class
    - ClientComposite.fractal
    - Server.class
    - Server.fractal
    - ServerAttributes.class
    - Service.class
    - Service.fractal
    - HelloWorld.fractal
Copyright © 1999-2005, ObjectWeb Consortium | contact | webmaster | Last modified at 2012-12-03 09:57 PM