The Fabric component provides a location discovery mechanism for Apache Camel routes. On the client side (producer endpoints), endpoints are represented by an abstract ID and at run time, the ID is resolved to a specific endpoint URI. Because the URI is stored in a distributed registry (provided by Fuse Fabric), this enables you to create flexible applications whose topology can be specified at deploy time and updated dynamically.
The Fabric component can only be used in the context of a fabric-enabled Fuse ESB Enterprise
container. You must ensure that the fabric-camel feature is installed. If
necessary, you can install it using the following console command:
karaf@root> features:install fabric-camel
Alternatively, if you decide to use a custom feature to deploy your application, you can
ensure that the fabric-camel feature is installed by including it in your
feature definition. For example:
<?xml version="1.0" encoding="UTF-8"?>
<features>
<feature name="fabric-component-example">
<feature>fabric-camel</feature>
<bundle>URIforMyBundle</bundle>
<!-- Specify any other required bundles or features -->
...
</feature>
</features>For more details about features, see Deploying Features in Deploying into the Container.
A fabric endpoint has the following URI format:
fabric:ClusterID[:PublishedURI[?Options]]
The format of the URI depends on whether it is used to specify a consumer endpoint or a producer endpoint.
For a Fabric producer endpoint, the URI format is:
fabric:ClusterID:PublishedURI[?Options]
Where the specified URI, , is
published in the fabric registry and associated with the
PublishedURI cluster.ClusterId
For a Fabric consumer endpoint, the URI format is:
fabric:ClusterIDWhere the client looks up the ID, , in
the fabric registry to discover the URI to connect to.ClusterId
The Fabric component itself does not support any URI options. It is possible, however, to specify options for the published URI. These options are stored in the fabric registry as part of the URI and are used as follows:
Server-only options—options that are applicable only to the server are applied to the server endpoint (consumer endpoint) at run time.
Client-only options—options that are applicable only to the client are applied to the client endpoint (producer endpoint) at run time.
Common options—options common to the client and the server are applied to both.
Fabric endpoints essentially provide a discovery mechanism for Apache Camel endpoints. For example, they support the following basic use cases:
Figure 1 gives an overview of how Fabric endpoints enable location discovery at run time.
The server side of this application is defined by a route that starts with a Fabric
endpoint, where the Fabric endpoint publishes the URI,
jetty:http://0.0.0.0:9090. When this route is started, it automatically
registers the Jetty URI in the fabric registry, under the cluster ID,
foo.
The client side of the application is defined by a route that ends with the Fabric
endpoint, fabric:foo. Now, when the client route starts, it automatically
looks up the ID, foo, in the fabric registry and retrieves the associated
Jetty endpoint URI. The client then creates a producer endpoint using the discovered Jetty
URI and connects to the corresponding server port.
Figure 2 gives an overview of how Fabric endpoints enable you to create a load-balancing cluster.
In this case, two Jetty servers are created, with the URIs,
jetty:http://0.0.0.0:9090 and jetty:http://0.0.0.0:9191.
Because these published URIs are both prefixed by fabric:foo:, both of the
Jetty URIs are registered under the same cluster ID, foo,
in the fabric registry.
Now, when the client routes starts, it automatically looks up the ID, foo,
in the fabric registry. Because the foo ID is associated with multiple
endpoint URIs, fabric implements a random load balancing algorithm to choose one of the
available URIs. The client then creates a producer endpoint, using the chosen URI.
Fabric endpoints support auto-reconnection. So, if a client endpoint (producer endpoint) loses its connection to a server endpoint, it will automatically go back to the fabric registry, ask for another URI, and then connect to the new URI.
To publish an endpoint URI, , in the
fabric registry, define a fabric endpoint with the publisher syntax,
PublishedURIfabric:.
Note that this syntax can only be used in a consumer endpoint (that is, an endpoint that
appears in a ClusterID:PublishedURIfrom DSL command).
Example 1 shows a route that implements a Jetty HTTP server, where
the Jetty URI is published to the fabric registry under the ID, cheese. The
route is a simply HTTP server that returns the constant message, Response from
Zookeeper agent, in the body of the HTTP response.
Example 1. Publishing a URI
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<reference id="org.linkedin.zookeeper.client.IZKClient"
interface="org.linkedin.zookeeper.client.IZKClient" />
<camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="fabric-server">
<from uri="fabric:cheese:jetty:http://0.0.0.0:9090/fabric"/>
<log message="Request received : ${body}"/>
<setHeader headerName="karaf.name">
<simple>${sys.karaf.name}</simple>
</setHeader>
<transform>
<simple>Response from Zookeeper agent</simple>
</transform>
</route>
</camelContext>
</blueprint>There are two points worth noting about the preceding sample code:
A reference to the
org.linkedin.zookeeper.client.IZKClientOSGi service is created using thereferenceelement. This reference is needed, because the Fabric component implicitly looks for anIZKClientobject in the bean registry and uses this object to connect to the underlying fabric.![[Note]](imagesdb/note.gif)
Note The
IZKClientOSGi service is provided by the fabric agent. Hence, a fabric agent must already be installed and running in the container where the route is deployed.The
fromDSL command defines the fabric URI,fabric:cheese:jetty:http://0.0.0.0:9090/fabric. At run time, this causes two things to happen:The specified
jettyURI is published to the fabric registry under the cluster ID,cheese.The Jetty endpoint is activated and used as the consumer endpoint of the route (just as if it had been specified without the
fabric:cheese:prefix).
Because the route is implemented in blueprint XML, you would normally add the file
containing this code to the src/main/resources/OSGI-INF/blueprint directory of
a Maven project.
To look up a URI in the fabric registry, simply specify the fabric endpoint URI with an
ID, in the format, fabric:. This syntax is
used in a producer endpoint (for example, an endpoint that appears in a ClusterIDto DSL
command).
Example 2 shows a route that implements a HTTP client, where the
HTTP endpoint is discovered dynamically at run time, by looking up the specified ID,
cheese, in the fabric registry.
Example 2. Looking up a URI
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<reference id="org.linkedin.zookeeper.client.IZKClient"
interface="org.linkedin.zookeeper.client.IZKClient"/>
<camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="fabric-client">
<from uri="timer://foo?fixedRate=true&period=10000"/>
<setBody>
<simple>Hello from Zookeeper server</simple>
</setBody>
<to uri="fabric:cheese"/>
<log message=">>> ${body} : ${header.karaf.name}"/>
</route>
</camelContext>
</blueprint>The client route also needs a reference to the
org.linkedin.zookeeper.client.IZKClient OSGi service, which the Fabric
component uses to connect to the underlying fabric.
Because the route is implemented in blueprint XML, you would normally add the file
containing this code to the src/main/resources/OSGI-INF/blueprint directory of
a Maven project.
In principle, implementing load balancing is easy using fabric endpoints. All that you have to do is to publish more than one endpoint URI under the same cluster ID. Now, when a client looks up that cluster ID, it gets a random selection out of the list of available endpoint URIs.
The servers in the load-balancing cluster have almost the same configuration. Essentially, the only difference between them is that they publish an endpoint URI with a different hostname and/or IP port. Instead of creating a separate OSGi bundle for every single server in the load-balancing cluster, however, it is better to define a template that enables you to specify the host or port using a configuration variable.
Example 3 illustrates the template approach to defining servers in a load-balancing cluster.
Example 3. Server Template for a Load-Balancing Cluster
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<!-- osgi blueprint property placeholder -->
<cm:property-placeholder id="placeholder" persistent-id="fabricCamel">
<cm:default-properties>
<cm:property name="portNumber" value="8181"/>
</cm:default-properties>
</cm:property-placeholder>
<reference id="org.linkedin.zookeeper.client.IZKClient"
interface="org.linkedin.zookeeper.client.IZKClient" />
<camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route id="fabric-server">
<from uri="fabric:cheese:jetty:http://0.0.0.0:{{portNumber}}/fabric"/>
<log message="Request received : ${body}"/>
<setHeader headerName="karaf.name">
<simple>${sys.karaf.name}</simple>
</setHeader>
<transform>
<simple>Response from Zookeeper agent</simple>
</transform>
</route>
</camelContext>
</blueprint>First of all, you need to initialize the OSGi blueprint property placehoder. The
property placehoder mechanism enables you to read property settings from the OSGi Config
Admin service and substitute the properties in the blueprint configuration file. In this
example, the property placeholder accesses properties from the fabricCamel
persistent ID. A persistent ID in the OSGi Config Admin service identifies a collection of
related property settings. After initializing the property placeholder, you can access any
property values from the fabricCamel persistent ID using the syntax,
{{.PropName}}
The Fabric endpont URI exploits the property placeholder mechanism to substitute the
value of the Jetty port, {{portNumber}}, at run time. At deploy time, you can
specify the value of the portName property. For example, if using a custom
feature, you could specify the property in the feature definition (see Add OSGi
configurations to the feature in Deploying into the Container). Alternatively, you can specify configuration
properties when defining deployment profiles in the Fuse Management
Console.
When defining an OSGi bundle that uses Fabric endpoints, the Import-Package
bundle header must be configured to import the following Java packages:
org.fusesource.fabric.zookeeper.spring org.linkedin.zookeeper.client
For example, assuming that you use Maven to build your application, Example 4 shows how you can configure the Maven bundle plug-in to import the required packages.
Example 4. Maven Bundle Plug-In Configuration
<project ... >
...
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>
org.fusesource.fabric.zookeeper.spring,
org.linkedin.zookeeper.client,
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
...
</project>








