|
Fraclet is both an implementation of the Fractal specifications conformed to the level 0.1, and an annotation framework for the Fractal component model. Fraclet is composed of several annotations and plugins to generate automatically various artifacts required by the Fractal component model. Annotations provide a way to describe the component meta-information directly in the source code of the content class. Fraclet plugins generate either Fractal component glue, FractalADL definitions or Monolog configurations.
This approach has several benefits:
Two implementations of the Fraclet annotation framework exist: Fraclet XDoc and Fraclet Annotation.
Fraclet uses the XDoclet2 as annotation parser and generation engine.
XDoclet is an open source code generation engine. It enables Attribute-Oriented Programming for java. In short, this means that you can add more significance to your code by adding meta data (attributes) to your java sources. This is done in special JavaDoc tags. This use of JavaDoc tags for attributes formed the original ideas for Java 5 Annotations.
XDoclet2 is the next generation of this technology. Based on Generama, it uses standard template engines such as Velocity and Freemarker for generation of text-oriented output, and Jelly for XML output. The function of XDoclet2 is to seed the generation contexts for these template engines.
XDoclet2 is supported by XDoclet2 plugins, which provide task-specific generation functionality.
This part describes the features of this XDoclet2 plugin for Fractal, and the way to use them.
Some annotations have been defined in order to describe the component meta-information. The list below describes these annotations.
Annotation | Location | Description |
---|---|---|
@provides | Class | Annotation to describe a Fractal server interface. |
@component | Class | Annotation to describe the controller part of a Fractal component. |
@data | Class | Annotation to describe a data used by a Fractal component. |
@monolog.handler | Class | Annotation to describe a custom Monolog handler. |
@attribute | Field | Annotation to describe an attribute of a Fractal component. |
@requires | Field | Annotation to describe a binding of a Fractal component. |
@control | Field | Annotation to provide a reflective control to the content of a Fractal component. |
@logger | Field | Annotation to define a logger for a Fractal component. |
@lifecycle | Method | Annotation to handle the lifecycle in a Fractal component. |
Details:
This class annotation adds the name information to the definition of a Fractal interface. This name is required by the Fractal component model to identify the interfaces required and provided by a Fractal component. This annotation can also override the associated interface signature to introduce interface meta-information at the class level.
Parameters:
Parameter | Description | Contingency |
---|---|---|
name | the name of the Fractal interface. | Optional (default value is the signature short name) |
signature | the signature of the Fractal interface. | Optional (default value is the Class signature) |
Examples:
/** @provides name=m */ public interface Main { ... } /** @provides name=r signature=java.lang.Runnable */ public class Client implements Runnable { ... }
Details:
This class annotation allows the developer to describe the description of the controller part that should be associated to the content part of the Fractal component.
Parameters:
Parameter | Description | Contingency |
---|---|---|
controller | the definition name of the controller part of the Fractal component. | Required |
template | the definition name of the controller part of the Fractal template component. | Optional |
Example:
/** @component controller=primitive */ public class Client implements Runnable { ... } /** @component controller=primitive template=primitiveTemplate */ public class Client implements Runnable { ... }
Details:
This class annotation provides a way to define a data used by a Fractal component.
Example:
/** @data */ public class Message { ... }
Details:
This class annotation allows the developer to describe a Monolog handler specific to the Fractal component. The available annotation attributes support the various properties that can be defined in a Monolog configuration file.
Parameters:
Parameter | Description | Contingency |
---|---|---|
name | the identifier of the handler. | Required |
type | the type of the handler. | Optional (default value is Console ) |
output | the output flow of the handler. | Optional (default value is System.out ) |
pattern | the output pattern of the handler. | Optional (default value is %l: %m%n ) |
max-size | the maximal size of the output file. | Optional |
file-number | the number of files used by the handler. | Optional |
append-mode | tag to use the handler in append mode (true |false ). | Optional (default value is false ) |
Example:
/** @monolog.handler name=clientHandler output=System.err pattern="%-5l [%h] <%t> %m%n" */ public class Client implements Runnable { ... }
Details:
This field annotation describes a Fractal attribute. A Fractal attribute is a Java attribute whose value can be configured and introspected from the Fractal component. Fractal attributes are managed by the attribute control feature of the Fractal component model.
Parameters:
Parameter | Description | Contingency |
---|---|---|
name | the name of the Fractal attribute. | Optional (default value is the Field name) |
argument | the name of the component argument used to configure the Fractal attribute. | Optional (default value is the Field name is no value is defined) |
value | the default value of the Fractal attribute. | Optional |
Example:
public class Client implements Runnable { /** @attribute name=count value=2 */ protected int counter; // field should be declared as protected or public. /** @attribute argument=client-prefix */ protected String pref; /** @attribute */ protected String suffix; ... }
Details:
This field annotation describes a Fractal binding. A Fractal binding is a Java attribute representing a client interface. Fractal bindings are managed by the binding control feature of the Fractal component model.
Parameters:
Parameter | Description | Contingency |
---|---|---|
name | the name of the Fractal binding. | Optional (default value is the Field name) |
signature | the signature of the Fractal binding. | Optional (default value is the Field signature) |
contingency | the contingency of the Fractal binding (mandatory |optional ). | Optional (default value is mandatory ) |
cardinality | the cardinality of the Fractal binding (singleton |collection ). | Optional (default value is singleton ) |
Example:
public class Client implements Runnable { /** @requires name=s signature=Service cardinality=collection */ protected Map servers = new HashMap(); // collections are stored in a map /** @requires */ protected Service service; ... }
Details:
This field annotation provides a way to refer a control interface provided by the controller part of the associated Fractal component.
Parameters:
Parameter | Description | Contingency |
---|---|---|
name | the name of the Fractal controller. | Optional (default value is component ) |
Example:
public class Client implements Runnable { /** @control name=name-controller */ protected NameController nc; // field should be declared as protected or public. /** @control */ protected Component self; ... }
Details:
This field annotation provides a way to define a Monolog logger to log the execution of the Fractal component.
Parameters:
Parameter | Description | Contingency |
---|---|---|
name | the name of the Monolog logger. | Optional (default value is the Class name) |
level | the level of the Monolog logger. | Optional (default value is INFO ) |
additivity | the additivity tag for the Monolog logger (true |false ). | Optional (default value is true ) |
clean-handlers | the clean-handlers tag for the Monolog logger (true |false ). | Optional (default value is true ) |
Example:
public class Client implements Runnable { /** @logger name=c handler="clientHandler,fileHandler" */ protected Logger log; // field should be declared as protected or public. /** @logger */ protected Logger log2; ... }
Julia Configuration:
To enable the Monolog support in Julia, the julia.cfg
configuration file should be modified to override the lifecycle-controller-impl
definition as follows:
... # LifeCycleController implementation (for primitive or composite components) (lifecycle-controller-impl ((org.objectweb.fractal.julia.asm.MixinClassGenerator LifeCycleControllerImpl org.objectweb.fractal.julia.BasicControllerMixin org.objectweb.fractal.julia.UseComponentMixin org.objectweb.fractal.julia.control.lifecycle.BasicLifeCycleCoordinatorMixin org.objectweb.fractal.julia.control.lifecycle.BasicLifeCycleControllerMixin # to check that mandatory client interfaces are bound in startFc: org.objectweb.fractal.julia.control.lifecycle.TypeLifeCycleMixin # to automatically assign the logger and logger factory: org.objectweb.fractal.julia.BasicInitializableMixin org.objectweb.fractal.julia.logger.LoggerLifeCycleMixin # to notify the encapsulated component (if present) when its state changes: org.objectweb.fractal.julia.control.lifecycle.ContainerLifeCycleMixin ) # optional initialization parameter (monolog configuration file name): (monolog-conf-file monolog.properties) ) ) ...
AOKell Configuration:
To enable the Monolog support in AOKell, the build.properties
configuration file should be modified to activate the feature.loggable.on
property as follows:
... # The loggable feature determines whether primitive components are equipped # with a monolog logger or not (which is the default case). # Uncomment the following property for using primitive components equipped # with a monolog logger. feature.loggable.on true ...
Details:
This method annotation provides a way to define a lifecycle handler supported by the controller part of the associated Fractal component.
Parameters:
Parameter | Description | Contingency |
---|---|---|
when | the lifecyle transition to handle (create |start |stop |destroy ). | Required |
Example:
public class Client implements Runnable { /** @lifecycle when=start */ protected void init() { System.out.println("Starting the component Client..."); } ... }
Some plugins have been defined in order to generate the component artifacts. The list below describes these plugins:
Plugin | Dependency | Description |
---|---|---|
AttributeControllerPlugin | - | Plugin to generate the AttributeController interface of a Fractal component. |
PrimitiveComponentPlugin | AttributeControllerPlugin | Plugin to generate the component glue class of a Fractal component. |
PrimitiveDefinitionPlugin | - | Plugin to generate the FractalADL definition associated to the Fractal component. |
CompositeDefinitionPlugin | PrimitiveDefinitionPlugin | Plugin to generate the FractalADL assembly definition containing the Fractal component. |
MonologConfigurationPlugin | - | Plugin to generate the Monolog configuration file associated to the Fractal components. |
Details:
Generates the <CLASS>Attributes
interface associated to a <CLASS>
class if it defines at least an attribute using the
@attribute
annotation.
Usage:
<target name="compile"> <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="classpath"/> <mkdir dir="${gen}"/> <xdoclet> <fileset dir="${src}" includes="**/*.java" /> <component destdir="${gen}" classname="org.objectweb.fractal.fraclet.AttributeControllerPlugin"/> </xdoclet> ... </target>
Details:
Generates the Fc<CLASS>
class associated to a <CLASS>
class.
class if it defines either a @attribute
,
@requires
,
@control
or/and
@logger
annotation.
Usage:
<target name="compile"> <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="classpath"/> <mkdir dir="${gen}"/> <xdoclet> <fileset dir="${src}" includes="**/*.java" /> <component destdir="${gen}" classname="org.objectweb.fractal.fraclet.PrimitiveComponentPlugin"/> </xdoclet> ... </target>
Generates the <CLASS>.fractal
definition associated to a <CLASS>
class (or interface).
Usage:
<target name="compile"> <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="classpath"/> <mkdir dir="${build}"/> <xdoclet> <fileset dir="${src}" includes="**/*.java" /> <component destdir="${build}" classname="org.objectweb.fractal.fraclet.PrimitiveDefinitionPlugin"/> </xdoclet> ... </target>
Details:
Generates the <CLASS>Composite.fractal
definition associated to a <CLASS>
class if it
defines at least a @requires
annotation.
Usage:
<target name="compile"> <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="classpath"/> <mkdir dir="${build}"/> <xdoclet> <fileset dir="${src}" includes="**/*.java" /> <component destdir="${build}" classname="org.objectweb.fractal.fraclet.CompositeDefinitionPlugin"/> </xdoclet> ... </target>
Details:
Generates the monolog.properties
configuration file for the Monolog tool.
Usage:
<target name="compile"> <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="classpath"/> <mkdir dir="${build}"/> <xdoclet> <fileset dir="${src}" includes="**/*.java" /> <component destdir="${build}" classname="org.objectweb.fractal.fraclet.MonologConfigurationPlugin"/> </xdoclet> ... </target>
This section provides a quick overview of the benefits of Fraclet. It shows that using annotations, Fractal source code becomes more concise and easier to maintain. It shows that using Fractlet, more than 60% of the source code (Java, FractalADL, properties) can be saved.
The source code below represents the Java code and the Fraclet annotations written to implement the Client
and the Server
Fractal components:
/** @provides name=r signature=java.lang.Runnable */ public class Client implements Runnable { /** @requires */ protected Service s ; /** @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 @provides
annotation.
The attribute s
is annoted as a client interface (using @requires
), which will be named s
as no name
parameter is defined.
The attribute message
is annoted as a Fractal attribute (using @attribute
), which will be automatically initialized to "Hello !"
.
/** @provides name=s */ public interface Service { void print(String message); }
The Service
interface is annoted with @provides
to define the name of the Fractal interface as s
.
public class Server implements Service { /** @attribute */ protected String header; /** @attribute */ protected 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.
The assembly definition below represents the FractalADL assembly defined to describe the HelloWorld
Fractal component:
<definition name="HelloWorld" extends="ClientComposite"> <component name="s" definition="Server('>>',2)"/> </definition>
This definition creates a composite component HelloWorld
extending the generated Client
abstract definition.
Then it specifies that the definition of the component named s
is FcServer
and that the values of the header
and the counter
attributes are '>>'
and 2
, respectively.
The following piece of XML presents the compilation process enhanced with the Fractal plugins.
<project name="helloworld" default="compile"> ... <target name="compile"> <taskdef name="xdoclet" classname="org.xdoclet.ant.XDocletTask" classpathref="classpath"/> <mkdir dir="${gen}"/> <mkdir dir="${build}"/> <xdoclet> <fileset dir="${src}" includes="**/*.java" /> <component destdir="${gen}" classname="org.objectweb.fractal.fraclet.AttributeControllerPlugin"/> <component destdir="${gen}" classname="org.objectweb.fractal.fraclet.PrimitiveComponentPlugin"/> <component destdir="${build}" classname="org.objectweb.fractal.fraclet.PrimitiveDefinitionPlugin"/> <component destdir="${build}" classname="org.objectweb.fractal.fraclet.CompositeDefinitionPlugin"/> <component destdir="${build}" classname="org.objectweb.fractal.fraclet.MonologConfigurationPlugin"/> </xdoclet> <javac srcdir="${src}:${gen}" destdir="${build}" classpathref="classpath"> <include name="**/*.java"/> </javac> <copy todir="${build}"> <fileset dir="${src}"> <exclude name="**/*.java"/> <exclude name="**/*.html"/> </fileset> </copy> </target> ... </project>
The directory structure below presents the list of compiled, generated and written files when using Fraclet to implement the HelloWorld example:
%example% * build/ - Client.class - Client.fractal - ClientAttributes.class - ClientComposite.fractal - FcClient.class - FcServer.class - HelloWorld.fractal - Server.class - Server.fractal - ServerAttributes.class - Service.class - Service.fractal * generated/ - ClientAttributes.java - FcClient.java - FcServer.java - ServerAttributes.java * src/ - Client.java - HelloWorld.fractal - Server.java - Service.java