Requirements

You must be familiar with Fractal before starting this tutorial:

Important note: The code presented in this page is available in the Julius distribution.

Table of contents

For this tutorial we will start with the Fractal comanche application (see Fractal tutorial).

The Comanche application

Comanche is a minimal HTTP server. Basically its role is to accept connections on a server socket, and for each connection, start a thread to handle the request. To do so, the server (1) analyzes the request, (2) logs it, (3) sends back the requested file or returns an error if the file does not exist.

From this short description we can extract the concerns of receiving the request, analyzing it, handling it, and logging it. Figure 1 presents the architecture we obtain from this decomposition. We have added a scheduler to the request receiver and we use a request dispatcher to separate the file server service from the error manager service. As a result, we obtain an application with a complete SoC. See the Fractal tutorial for a complete description of this example.

Figure 1: The comanche application

The need for AOP

Now we want to extend the architecture to add support for logging. Suppose we want to extend the role of the current Logger component to the Request Dispatcher. This operation impacts several components as illustrated in Figure 2. In a component only approach, the integration of logging would require us to scatter logging code into several components. As a result, all these components would tangle their primary concern with transaction management concern. Here we see the limit of explicit dependencies in CBSD. It does not yield a clean SoC as soon as crosscutting concerns are needed.

Figure 2: The tangling with the component only approach

Step 1: Defining the logging concern (reuse the Logger as an aspect)

FAC is a symmetrical approach (see FAC overview), so the behavior of the log aspect is written as a plain component. So we can use the Logger of Figure 1 as it is. Only an aspect connector is required to connect the logging service in an aspect-oriented way.

Figure 3: The comanche application with an aspect connector

The wanted composition feature is represented in Figure 3. The Logger has been extracted into a new composite logging, and we can see an aspect connector making the connection to the Request Analyzer and to the Request Dispatcher. As explained in the FAC overview, the aspect connector is actually composed of several concepts, added to the Fractal component model. Basically, to weave the Logger to the Request Analyzer and the Dispatcher, an aspect component is required and it has to be woven on the architecture. We now describe these steps.

Step 2: Defining a Logging Aspect Component

In this step we will define an aspect component which delegates its interception context to the Logger by simply calling it through a regular Fractal binding.

 @AspectComponent
 public class LoggerAC implements AdviceInterface {
        // The LoggerAC requires the logger interface from the Logger component
	@Requires(name = "logger")
	private ILogger logger;
         // Implementation of the AspectComponent interface
	public Object invoke(FcMethodInvocation m) throws Throwable {
                logger.log(m.getComponentName() + " before method " 
                                    + m.getMethod().getName());
                Object ret = m.proceed();
                logger.log("/// Trace AC: after method "+ m.getMethod().getName());
                return ret;   
	}
 }
The above code presents the implementation of the Logging AC. The class is annotated @AspectComponent and implements the AdviceInterface. An aspect component in FAC is a component providing an advice code as a server interface. Aspect components are used as aspect-oriented component connectors. An aspect component is working on an interception context, which is reified here as the parameter of the invoke method (FcMethodInvocation). In FAC, aspects apply to incoming and outgoing calls on component interfaces. So here, the LoggingAC aspect component will apply to intercepted operations of the Request Analyzer and Request Dispatcher components. The next step explains how to capture component operations. Here we just specified the behavior of the aspect.

One may notice that the aspect component is simply calling the Logger component (green code). This is the application of a AOSD best practice of delegating the implementation of the aspect to a reusable component. In our case the logger, which is already available for use. Figure 4 shows how the Logger AC and the Logger component are bound together.

Figure 4: The logger aspect component and the logger component

Step 3: Weaving the aspect component

In this step, we will weave the Logging Aspect Component to the Comanche architecture. For this task we need to define a pointcut, pick a root composite, which will be introspected, and name for the aspect domain. The following pointcut will fullfil our requirements : ... We choose the Comanche composite as the root of the weaving. Finally we will give the name LoggingAD for the aspect domain, which will reify the domain of influence of the Logging Aspect Component.

Figure 5: The comanche application with the Logger fully integrated

Option 1: Weaving using Fractal-ADL

Weaving with Fractal-ADL is straightforward in FAC. 2 new tags are introduced to support this: the aspect binding tag, and the weaving tag (see dtd definition below).
 <!ELEMENT aspectBinding (comment*) >
 <!ATTLIST aspectBinding
  pointcutExp CDATA #REQUIRED
  ac CDATA #REQUIRED
 >

 <!ELEMENT weave (comment*) >
 <!ATTLIST weave
  root CDATA #REQUIRED
  ac CDATA #REQUIRED
  pointcutExp CDATA #REQUIRED
  aDomain CDATA #REQUIRED
 >
 
Back to our log example, the weaving of the Log aspect component would be performed as follows
<definition name="comanche.ComancheComposite" > <interface name="r" signature="java.lang.Runnable" role="server" cardinality="singleton" contingency="mandatory"/> <component name="fe" definition="comanche.FrontendComposite" /> <component name="be" definition="comanche.BackendComposite" /> <-- Definition of the aspect component --> <component name="traceAC" definition="hw.TraceAC" /> <binding client="this.r" server="fe.r" /> <binding client="fe.rh" server="be.rh" /> <-- Definition of the weaving task --> <weave root="this" ac="traceAC" pointcutExp="ra;*;*" aDomain="traceAD" /> <controller desc="aspectComposite"/> </definition>
Or, you may use Adlet which is an extension of Fraclet included into Julius, which allows to annotate a class to transform it as a composite definition (see the example below).
 // Composite definition
 @FractalComposite(controllerDesc = "aspectComposite")
 @Provides(interfaces = @Interface(name = "r", signature = Runnable.class))
 public class ComancheAspect {
         // Definition of sub-components 
	FrontendComposite fe;
	BackendComposite be;
         // Definition of bindings (just annotate a method), the name of the method
          // corresponds to the name of the binding
	@Binding(client="this", server="fe")
	void r(){}
	@Binding(client="fe", server="be")
	void rh() {}
	// Definition of the aspect component
	TraceAC traceAC;
	// Definition of the weaving task (name of the method is the name of the aspect domain)
	@Weave(root = "this", acName = "traceAC", pointcutExp = "ra;*;*")
	void traceAD() {}
 }

Option 2: Weaving using Fractal-Explorer

Fractal Explorer is a Fractal tool to minitor running Fractal application. We have extended Fractal Explorer ot support the dynamic weaving of aspect components.