Fabric3 is built on Service Component Architecture (SCA). In SCA, application code is organized as a set of components. A component may have one or more services it exposes to clients and may contain references to other services it depends on. A component may be implemented as a Java class. The following illustrates a calculator component written in Java (taken from the samples) that is wired to operand services:
public class CalculatorServiceImpl implements CalculatorService { @Reference protected AddService addService; @Reference protected SubtractService subtractService; @Reference protected MultiplyService multiplyService; @Reference protected DivideService divideService; public double add(double n1, double n2) { return addService.add(n1, n2); } public double subtract(double n1, double n2) { return subtractService.subtract(n1, n2); } public double multiply(double n1, double n2) { return multiplyService.multiply(n1, n2); } public double divide(double n1, double n2) { return divideService.divide(n1, n2); } } |
A component is defined and configured in XML:
<component name='SampleComponent'> <implementation.java class="org.sample.SampleComponent"/> </component> |
Applications are composed of one or more composites. A composite is an XML file that contains a set of component definitions:
<composite xmlns='http://docs.oasis-open.org/ns/opencsa/sca/200912' targetNamespace='urn:tempuri.org' name='SampleComposite'> <component name='SampleComponent'> <implementation.java class="org.sample.SampleComponent"/> </component> </composite> |
A composite is similar to a Spring application context but with several important differences:
Components can provide one or more services to clients. Clients may be remote or local. For remote clients, a component service can be exposed as an endpoint using a binding such as WS-*, JAX-RS or JMS. The following demonstrates how to expose an endpoint to a JMS queue:
<composite ...> <component name='TargetComponent'> <implementation.java class="org.sample.TargetComponent"/> <service name="TargetService"> <binding.jms> <destination jndiName="SampleQueue"/> </binding.jms> </service> </component> </composite> |
A component can act as a client to a service by wiring a reference:
<composite ...> <component name='SampleComponent'> <implementation.java class="org.sample.SampleComponent"/> <reference name="service" target="TargetComponent"/> </component> <component name='TargetComponent'> <f3:implementation.java class="org.sample.TargetComponent"/> </component> </composite> |
In the above example, the wire from SampleComponent/service to TargetComponent can be local or remote (possibly passing through a message queue) depending on if the two components are collocated.
Fabric3 also supports pub/sub interactions where components pass events through a channel as opposed to being directly wired. A component producer is connected to a channel, which in turn may be connected to 0..N component consumers. The following shows how to create an event network using a channel:
<composite ...> <channel name="SampleChannel"/> <component name='SampleComponent'> <implementation.java/> <producer name="channel" target="SampleChannel"/> </component> <component name='TargetComponent1'> <implementation.java/> <consumer name="channel" source="SampleChannel"/> </component> <component name='TargetComponent2'> <implementation.java/> <consumer name="channel" source="SampleChannel"/> </component> </composite> |
Channels may be local or remote depending on where its producers and consumers are deployed. In the case where producers and consumers are remote, Fabric3 will bind a channel to a remote transport such as a JMS topic (channels may also be explicitly bound using the <binding> element in a composite).