Java Components

Fabric3 supports creating components using Java classes (POJOs). The only requirement placed on a component implementation is that it is a class which implements an interface defining the service contract clients invoke it using (in some cases, such as the JAX-RS binding, an interface is not required).

Basics

The following illustrates part of a Java component:

@Component 
public class CalculatorServiceImpl implements CalculatorService {

    @Reference
    protected AddService addService;

    @Property
    protected int maxValue; 
  
    public double add(double n1, double n2) {
        return addService.add(n1, n2);
    }
    
    ......
}

References and Properties

In the above example, the CalculatorServiceImpl component reference another service, AddService. This service can be local (in which case invocations are done in memory) or remote (in which case invocations are done over a remote transport such as ZeroMQ, a messaging provider or HTTP). Fabric3 uses dependency injection to provide services references.  At runtime, Fabric3 will inject service proxies on constructor parameters, methods and fields annotated with @Reference. These proxies are responsible for dispatching to a target service whether it is local in the same VM or remote. References can either be explicitly configured (more on that in a minute) or autowired, in which case Fabric3 will match a target service by contract.    

The previous component example also contains a field annotated with @Property. Properties are configured along with the component and values will be injected at runtime.

Fabric3 supports constructor-based, field-based and method-based injection of references and properties. Choose the style that you are most comfortable with.

Configuring a Component

As an alternative to the Component annotation and DSL approaches, a component can be defined and configured in an XML called a composite instead of using the Component annotation. The following outlines how this is done:

<composite name="MyComposite" ...>
 
   <component name='CalculatorService'>
      <implementation.java class="org.sample.CalculatorServiceImpl"/>
      <reference name="addService" target="AddService"/>
      <property name="maxValue">5</maxValue>
   </component>

 
</composite>

Services

Components typically offer one or more services that clients invoke. If a component implements a single interface, it provides one service as defined by the interface. It may be necessary to explicitly define the service a component offers, for example, if it implements more than one interface. This is done using the SCA Service annotation:

@Component
@Service(CalculatorService.class)
public class CalculatorServiceImpl implements CalculatorService {
    ...
}  

 Services may be bound to a remote transport so that they can be invoked by (or receive messages from) remote clients. The Bindings section provides details on how this is done.

Scopes

One of the most important concepts to understand when creating a component is its scope. A scope defines the component lifecycle. Fabric3 supports the following scopes:

  • Stateless
  • Composite
  • Domain

Scopes are defined using the org.oasisopen.sca.annotation.Scope annotation:

 

@Component
@Scope("COMPOSITE")
public class CalculatorServiceImpl implements CalculatorService {
    ...
}  

 

Valid values are: DOMAIN, COMPOSITE, and STATELESS (the default if not specified). Alternatively, Fabric3 provides typed scope annotations in the org.fabric3.api.annotation.scope package of the fabric3-api module (the Maven coordinates are org.codehaus.fabric3:fabric3-api). 

Stateless Components

For each request, the Fabric3 runtime instantiates a new instance of a stateless-scoped component and dispatches to it. This means that a stateless scoped component will only be running on one thread at a time. If a stateless-scoped component declares @Init and @Destroy methods, they will be called before and after each request is dispatched respectively. Stateless scope is the default if not specified.

Composite Components

Only one instance of a composite-scoped component exists on a runtime. This means multiple requests may be dispatched to the component instance simultaneously. If a composite-scoped component declares an @Init method, it will be called when the composite containing the component is deployed. If it declares an @Destroy method, it will be called when the composite is undeployed.

Domain Components

Only one instance of a domain-scoped component exists in a zone at a time. A domain-scoped component will be instantiated on the runtime elected as a zone leader. If the runtime fails or becomes unavailable, a new component instance will be instantiated on the newly elected zone leader. If a domain-scoped component declares an @Init method, it will be called when the component instance is created. If it declares an @Destroy method, it will be called when the composite containing the component is undeployed.

Optimizations

Composite-scoped components should be preferred to stateless components. This is because they avoid excessive object creation and instance lookup at the expense of requiring thread safety. In addition, Fabric3 may optimize wiring to composite-scoped components by injecting the actual reference on client components that are collocated. This direct injection can be performed if the wire does not contain policies such as transactions that require invocation interception.

 

For more details on creating Java components, see the Starter Applications samples and Understanding SCA.