Fractal - Fraclet | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
About this documentThis document is a tutorial of the Fraclet Annotation implementation of the Fraclet Framework.
Table of Contents1. Fraclet Annotation: A Java 5 annotation support for FractalFraclet is the annotation framework of the Fractal component model. Fraclet provides an annotation-oriented programming (@OP) style for developing Fractal applications. Fraclet leverages the process a writting a Fractal application by providing a set of annotations which reduces the amount of code which must be written by developers. Fraclet-annotation is an implementation of Fraclet using Java5 annotations and Spoon, an Java 5 annotation-driven open compiler and program transformation tool. About SpoonIn 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 usefull to express patterns that can be used for generating code, as exampled by Generative Programming. To implement Fraclet-annotation with have used a set of Spoon processors and templates to process our defined annotations. This tutorial doesn't detail the implementation of the processors and templates but explain how to use Fraclet-annotation annotations and how features are generated or transformed. 1.1 Available AnnotationsSome annotations have been defined in order to describe the component meta-information. The list below describes these annotations.
Note that the @FractalComponent, @Interface, @Provides, and @Requires annotations are used together to generate .fractal files for Fractal-ADL. See the revisiting of the Hello World example for more details In addition to these generic component annotations, two more annotations are used to generate monolog configuration file and getter/setter for the logger and the logger factory.
@FractalComponentDetails: This interface annotation is used to generate the .fractal file associated to a Fractal component. The processor associated to this annotation works with all the other annotations to retrieve the informations required to generate a concrete definition of the component: its name, its required interfaces, its provided interfaces, and its attributes. Parameters:
Examples: @FractalComponent(controllerDesc="MyPrimitiveType") public class MyComponent { ... } will generate the following .fractal definition: <component name="MyComponent"> (...) <controller desc="MyPrimitiveType"/> </component> @InterfaceDetails: This interface annotation has to be used on Java interfaces that need to be used as Fractal interfaces. This annotation is also used by the @FractalImportedInterface annotation as a nested annotation. IMPORTANT NOTE: you don't need to put again this annotation on content classes which provide this interface. Thanks to Spoon meta model, this information is automatically computed. So you just need to annotate your interface with @Interface, your component with @FractalComponent, and the processor of the @FractalComponent annotation will automatically see that you implement an interface that is annotated with @Interface Parameters:
Examples: @Interface(name="service") public interface Service { ... } ...will generate the following Fractal ADL abstract definition: <definition name="Service"> <interface name="service" signature="Service" role="server" cardinality="singleton" contingency="mandatory"/> </definition> ... and the combination of the @FractalComponent and @FractalItf annotations of the following example: @Interface(name="service") public interface Service { (...) } @FractalComponent public class ServerA implements Service { (...) } ... will provide the following Fractal-ADL definitions: <definition name="Service"> <interface name="service" signature="Service" role="server" cardinality="singleton" contingency="mandatory"/> </definition> <definition name="ServerA" extends="Service"> <content class="ServerA"/> </definition> @ProvidesDetails: This class annotation handles the particular case of imported Fractal interface, i.e., Java interfaces that are not annotated with @Interface, but directly used as Fractal interfaces. The best example of this is the java.lang.Runnable interface which is regularly used to start a Fractal application. This annotation use nested annotations which are @Interface annotations. This allows the definition of multiple imported interfaces. Parameters:
Examples: @FractalComponent @Provides(interfaces=@Interface(name="r",signature=java.lang.Runnable.class)) public class Client implements Runnable { (...) } ...will generate the following Fractal ADL abstract definition: <definition name="Client"> <interface name="r" signature="java.lang.Runnable" role="server" cardinality="singleton" contingency="mandatory"/> <content class="Client"/> </definition> @AttributeDetails: 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. The @Attribute will transform the original class to introduce getter/setter, and generate a new interface for these getter/setter. See the examples below. Used with the @FractalComponent annotation, the Fractal-ADL definition of the Fractal attribute are also generated. Parameters:
Examples: The following example: public class ServerA implements Service { @Attribute(value=">>") private String header ; @Attribute(argument="msg") private String message ; (...) } ... will introduce the following getter/setter methods and generate a ServerAAttributeController interface just as follows: public class ServerA implements ServerAAttributeController { (...) /** * This method has been automatically injected by Spoon * * @return the reference of the field */ public String getHeader() { return header; } /** * This method has been automatically injected by Spoon * * @return the reference of the field */ public String getMessage() { return message; } /** * This method has been automatically injected by Spoon * * @param value * the value to set to the field */ public void setHeader(String value) { header = value; } /** * This method has been automatically injected by Spoon * * @param value * the value to set to the field */ public void setMessage(String value) { message = value; } } public interface ServerAAttributeController extends AttributeController { /** * This method has been automatically injected by Spoon * * @return the reference of the field */ public String getHeader(); /** * This method has been automatically injected by Spoon * * @return the reference of the field */ public String getMessage(); /** * This method has been automatically injected by Spoon * * @param value * the value to set to the field */ public void setHeader(String value); /** * This method has been automatically injected by Spoon * * @param value * the value to set to the field */ public void setMessage(String value); } The combination of the @FractalComponent and @Attribute annotations of the following example: @FractalComponent public class ServerA implements Service { @Attribute(value=">>") private String header ; @Attribute(argument="msg") private String message ; (...) } ... will provide the following Fractal-ADL definitions: <definition name="ServerA" arguments="msg"> <content class="ServerA"/> <attributes signature="ServerAAttributeController"> <attribute name="message" value="${msg}"/> <attribute name="header" value=">>"/> </attributes> </definition> @RequiresDetails: 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. Used with the @FractalComponent annotation, the Fractal-ADL definition of the Fractal attribute are also generated. See the following examples. Parameters:
Examples: public class Client implements Runnable { @Requires(name = "default") private Service defaut; // signature of the Fractal binding is computed because the Map is well typed @Requires(name = "service", cardinality = Cardinality.COLLECTION) private Map<String,Service> services = new HashMap<String,Service>(); } ... will transform the Client class into the following: public class Client implements Runnable { private Service defaut; // signature of the Fractal binding is computed because the Map is well typed private Map<String,Service> services = new HashMap<String,Service>(); /** * (non-Javadoc) * * @see org.objectweb.fractal.api.control.BindingController#bindFc(java.lang.String, * java.lang.Object) Method automatically generated with Spoon * <http://spoon.gforge.inria.fr> */ public void bindFc(String clientItfName, Object serverItf) throws NoSuchInterfaceException, IllegalBindingException { if (clientItfName.equals("default")) { if (!Service.class.isAssignableFrom(serverItf.getClass())) { throw new IllegalBindingException((("server interfaces connected to " + clientItfName) + " must be instances of ") + (Service.class.getName())); } defaut = ((Service)(serverItf)); return ; } if (clientItfName.startsWith("service")) { if (!Service.class.isAssignableFrom(serverItf.getClass())) { throw new IllegalBindingException((("server interfaces connected to " + clientItfName) + " must be instances of ") + (Service.class.getName())); } services.put(clientItfName ,((Service)(serverItf))); return ; } throw new NoSuchInterfaceException(("Client interface \'" + clientItfName) + "\' is undefined."); } /** * (non-Javadoc) * * @see org.objectweb.fractal.api.control.BindingController#listFc() Method * <http://spoon.gforge.inria.fr> */ public String[] listFc() { List<String> __interfaces__ = new ArrayList<String> (); __interfaces__.add("default"); __interfaces__.addAll(services.keySet()); return __interfaces__.toArray(new String[]{ }); } /** * (non-Javadoc) * * @see org.objectweb.fractal.api.control.BindingController#lookupFc(java.lang.String) * Method automatically generated with Spoon * <http://spoon.gforge.inria.fr> */ public Object lookupFc(String clientItfName) throws NoSuchInterfaceException { if (clientItfName.equals("default")) { return defaut; } if (clientItfName.startsWith(clientItfName)) { return services.get(clientItfName); } throw new NoSuchInterfaceException(("Client interface \'" + clientItfName) + "\' is undefined."); } /** * (non-Javadoc) * * @see org.objectweb.fractal.api.control.BindingController#unbindFc(java.lang.String) * Method automatically generated with Spoon * <http://spoon.gforge.inria.fr> */ public void unbindFc(String clientItfName) throws NoSuchInterfaceException { if (clientItfName.equals("default")) { defaut = null; return ; } if (services.containsKey(clientItfName)) { services.remove(clientItfName); return ; } throw new NoSuchInterfaceException(("Client interface \'" + clientItfName) + "\' is undefined."); } } The combination of the @FractalComponent and @Requires annotations of the following example: @FractalComponent public class Client implements Runnable { @Requires(name = "default") private Service defaut; @Requires(name = "service", cardinality = Cardinality.COLLECTION) // signature of the Fractal binding is computed because the Map is well typed private Map<String,Service> services = new HashMap<String,Service>(); } ... will provide 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> @LifeCycleDetails: This method annotation provides a way to define a lifecycle handler supported by the controller part of the associated Fractal component. Parameters:
Example: @FractalComponent public class Client implements Runnable { @LifeCycle(on=LifeCycleType.START) private void init() { System.out.println("Starting the component Client..."); } (...) } @ServiceDetails: This field annotation provides a way to get a component service. So far, only one service is implemented: "component". This service gives the reference of the Component part. Parameters:
Example: public class Client implements Runnable { @Service("component") private Component c; } @MonologHandlerDetails: 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:
Example: @MonologHandler(name="clientHandler", output="System.err", pattern="%-5l [%h] <%t> %m%n") public class Client implements Runnable { ... } @MonologDetails: This field annotation provides a way to define a Monolog logger to log the execution of the Fractal component. Parameters:
Example: public class Client implements Runnable { @Monolog (name="c", handler="clientHandler,fileHandler") private Logger log; @Monolog private Logger log2; ... } Julia Configuration: To enable the Monolog support in Julia, the ... # 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 ... # 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 ... 1.2 Revisiting the HelloWorld ExampleThis 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. HelloWorld Architecture OverviewThe figure below introduces the well-known HelloWorld example implemented with Fractal components.
HelloWorld ImplementationThe source code below represents the Java code and the Fraclet annotations written to implement the @FractalComponent @Provides(interfaces=@Interface(name="r",signature=java.lang.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 @Interface(name="s") public interface Service { void print(String message); } The @FractalComponent 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 HelloWorld Architecture DefinitionThe assembly definition below represents the FractalADL assembly defined to describe the <definition name="HelloWorld"> <component name="client" definition="Client"; <component name="server" definition="Server('>>',2)"/> <binding client="this.r" server="client.r"/> <binding client="client.s" server="server.s"/> </definition> This definition creates a composite component Directory StructureThe 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 - ClientAttributeController.class - Server.class - Server.fractal - ServerAttributeController.class - Service.class - Service.fractal - HelloWorld.fractal * generated/ - Client.java - Client.fractal - ClientAttributeController.java - Server.java - Server.fractal - ServerAttributeController.java - Service.java - Service.fractal * src/ - Client.java - HelloWorld.fractal - Server.java - Service.java 2. Fraclet AvailabilityFraclet is freely available under an LGPL licence at the following URLs:
3. Dissemination
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Copyright © 1999-2005, ObjectWeb Consortium | contact | webmaster | Last modified at 2012-12-03 09:57 PM |