LibraryLink ToToggle FramesPrintFeedback

Deploying an XML Route

This section explains how to create a simple FUSE Mediation Router application and how to deploy it as an OSGi bundle into the FUSE ESB OSGi container. The examples in this section are taken from the camel-osgi demonstration, which defines a simple route in a Spring XML configuration file.

The camel-osgi demonstration is located in the following directory:

InstallDir/examples/camel-osgi

The demonstration shows how to define a route in XML, where the route is built up from the following parts:

The route is deployed into the FUSE ESB container as an OSGi bundle.

Relative to the CLASSPATH, the application's Spring XML file must be located in the following directory:

META-INF/spring

When you start an application bundle in the FUSE ESB OSGi container, Spring looks for any files matching *.xml located in META-INF/spring and processes all of the matched files. In effect, the Spring XML files located in this directory bootstrap the bundled application.

Example 1.1 shows the routes for the camel-osgi demonstration, taken from the Spring XML configuration file, META-INF/spring/beans.xml.

Example 1.1. Spring XML File Defining a Route

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" 1
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2
       xmlns:osgi="http://activemq.apache.org/camel/schema/osgi" 3       
       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium" 4
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://activemq.apache.org/camel/schema/spring http://activemq.apache.org/camel/schema/spring/camel-spring.xsd
       http://activemq.apache.org/camel/schema/osgi http://activemq.apache.org/camel/schema/osgi/camel-osgi.xsd
       http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

  <osgi:camelContext xmlns="http://activemq.apache.org/camel/schema/spring"> 5
    <route> 6
      <from uri="timer://myTimer?fixedRate=true&amp;period=2000"/>
      <bean ref="myTransform" method="transform"/>
      <to uri="log:ExampleRouter"/>
    </route>
  </osgi:camelContext>

  <bean id="myTransform" class="org.apache.servicemix.examples.camel.MyTransform"> 7
    <property name="prefix" value="${prefix}"/> 8
  </bean>

  <osgix:property-placeholder persistent-id="org.apache.servicemix.examples"> 9
    <osgix:default-properties>
      <prop key="prefix">MyTransform</prop>
    </osgix:default-properties>
  </osgix:property-placeholder>

</beans>

1

The default namespace, http://www.springframework.org/schema/beans, is the Spring XML namespace. This namespace provides access to the Spring configuration schema, which is used to instantiate and configure Java objects. In particular, the beans element, which contains all of the application's configuration, belongs to this namespace.

2

The XML schema namespace, http://www.w3.org/2001/XMLSchema-instance, gets associated with the xsi prefix. The XML schema provides access to standard XML data types and enables you to define new XML types and elements (here it is needed for the xsi:schemaLocation attribute).

3

The Camel/OSGi namespace, http://activemq.apache.org/camel/schema/osgi, gets associated with the osgi prefix. The Camel/OSGi schema is a simple schema that is used to define FUSE Mediation Router routes inside an OSGi container. Currently, this schema defines just a single element, osgi:camelContext.

4

The OSGi compendium namespace, http://www.springframework.org/schema/osgi-compendium, gets associated with the osgix prefix. The OSGi compendium schema provides additional features for Spring/OSGi integration, where these features are based on the OSGi Service Platform Service Compendium specification.

For more details, see Spring Compendium Services.

5

The contents of the osgi:camelContext element are defined using the regular Camel schema, http://activemq.apache.org/camel/schema/spring. The Camel schema enables you to define all of the routes for your FUSE Mediation Router application. See Using the Router Schema in an XML File.

6

Each route is defined using a route element and you can define multiple route elements in an osgi:camelContext element. In this example, the route starts with a FUSE Mediation Router timer component, which generates a hearbeat event every 2000 ms. Each event message is passed through a bean reference, which calls the transform() method on the bean with ID, myTransform, in order to process the message. Finally, the transformed message is sent to a Jakarta commons logging endpoint, log:ExampleRouter, using the FUSE Mediation Router log component.

For more details about how to define XML routes, see Defining Routes in XML.

7

The bean element instantiates the transformer bean using standard Spring syntax. When Spring parses this bean element, it creates a new instance of the class, org.apache.servicemix.examples.camel.MyTransform, by calling its default constructor. The property element is used to initialize the value of a Java bean property. In this case, the effect is that Spring calls the MyTransform.setPrefix() method, passing in the string, MyTransform. Finally, Spring enters the newly instantiated bean in its registry, using the ID value, myTransform. This enables other parts of the configuration to access the bean (for example, using a tag like <bean ref="IDValue" .../>).

For more details about how to instantiate Java classes using Spring, see The IoC Container chapter in the Spring documentation.

8

The prefix value is specified using a property placeholder, ${prefix}, which enables you to source bean property values from the OSGi Configuration Admin service.

[Note]Note

Using property placeholders is optional. You can specify the literal value of the property here, if you prefer.

9

The presence of the osgix:property-placeholder element in the Spring XML file enables the property placeholder feature from the Spring compendium services. In particular, this feature enables you to specify placeholder values, like ${KeyName}, using the standard OSGi Configuration Admin service. This example also specifies a default value for the property.

Example 1.2 shows the definition of a transformation bean class, org.apache.servicemix.examples.camel.MyTransform, which is responsible for transforming the body of the In message in a route. The MyTransform.transform() method from this class gets called by the preceding XML route (see Example 1.1).

Example 1.2. Transformation Bean Example

package org.apache.servicemix.examples.camel;

import java.util.Date;

import org.apache.commons.logging.Log; 1
import org.apache.commons.logging.LogFactory;

public class MyTransform  {
    private static final transient Log LOG = LogFactory.getLog(MyTransform.class);
    private boolean verbose = true;
    private String prefix = "MyTransform";

    public Object transform(Object body) { 2
        String answer = prefix + " set body:  " + new Date();
        if (verbose) {
            System.out.println(">>>> " + answer);
        }
        LOG.info(">>>> " + answer);
        return answer; 3
    }

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) { 4
        this.prefix = prefix;
    }
    ...
}

1

The org.apache.commons.logging package is external to the camel-osgi demonstration bundle. For details of how to access external packages, see Configuring the bundle headers.

2

The transform() method is responsible for performing the message transformation. The signature of this transformation method conforms to the following syntax:

  • The method takes a single parameter of Object type, representing the body of the In message.

  • The method declares a return value of Object type, representing the transformed body of the In message.

  • The name of the method can be anything you like.

There are other ways of defining bean transformation methods—for more details, see Bean Integration.

3

In this example, the body of the incoming message is ignored and the transformed message, answer, is a simple string containing a date and time stamp.

4

The setPrefix() method is a simple example of a bean property that can be initialized from within a Spring XML file (see Example 1.2).

In order to package the demonstration as an OSGi bundle (which is simply a JAR file), it is necessary to add a number of entries to the JAR's manifest file. Relative to the JAR root, the manifest file is stored in the following location:

META-INF/MANIFEST.MF

Where the pathname of this location is case-insensitive. For example, meta-inf/Manifiest.mf would work just as well. Example 1.3 shows the manifest for the camel-osgi bundle, which includes some OSGi-specific manifest entries, known as bundle headers.


Some of these manifest entries (for example, Bnd-LastModified, Build-Jdk, Private-Package, and Tool) are generated by the Maven bundle plug-in for information purposes only and they are thus not particularly important. Some of the OSGi bundle headers are also included for information only. The important entries are the bundle headers that affect the interaction between the bundle and the OSGi container and these are, as follows:

Bundle-Name:

A human-readable name for the current bundle. For example, when you enter the command, osgi list, from the FUSE ESB console, the installed bundles are listed with their bundle name.

Bundle-SymbolicName:

A unique name for the current bundle. The bundle symbolic name is the primary way of identifying a bundle. For example, you would use the bundle symbolic name to refer to a bundle from within a piece of code or in a configuration file. The usual convention for a bundle symbolic name is to use a reverse URL format (the sample value shown here is unconventional in this respect).

Import-Package:

The value of this header is a comma-separated list of Java package names for all of the packages needed by, but not included in this bundle. For example, the org.apache.commons.logging package is listed here because it is used by the transformation bean code.

[Note]Note

The syntax of the package list can be a bit more complicated than a comma-separated list (for example, you can optionally select particular package versions and so on). For full details of the syntax, consult the OSGi specification.

Export-Package:

(Not used in the example) The value of this header is a comma-separated list of Java package names for packages contained in the current bundle that you want to make available to other bundles. The Export-Package: and Import-Package: headers are complementary: the Java packages exported by one bundle using Export-Package: become available to other bundles that import them using Import-Package:.

Creating the contents of these headers can be an annoying chore, if you have to do it by hand. For example, a moderately complex piece of Java code might need to import dozens of different packages using the Import-Package: header. For larger applications, it would be convenient to have some way of automatically generating bundle headers.

If you are using the Apache Maven2 build system to build your application, you have the option of using the Maven bundle plug-in to generate all of the bundle headers automatically. As already noted, this feature can be extremely convenient for large, complex applications. Example 1.4 shows how to modify the top-level Maven build file, pom.xml, in order to enable the bundle plug-in.

Example 1.4. Configuration of Maven Bundle Plug-In in pom.xml File

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    ...
    <groupId>org.apache.servicemix.examples</groupId>
    <artifactId>camel-osgi</artifactId>
    <packaging>bundle</packaging> 1
    <version>4.0.0.2-fuse</version>
    <name>Apache ServiceMix Example :: Camel OSGi</name>
    ...
    <dependencies>
        <dependency> 2
            <groupId>org.apache.felix</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>1.0.0</version>
        </dependency>
        ...
    </dependencies>
    ...
    <build>
        <plugins>
            <plugin> 3
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
                        <Import-Package>*,org.apache.camel.osgi</Import-Package>
                        <Private-Package>org.apache.servicemix.examples.camel</Private-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
        ...
    </build>
    ...
</project>

1

Change the packaging from jar to bundle.

2

Add a dependency on the Apache Felix library, as shown.

[Note]Note

In the POM file for the camel-osgi demonstration, this dependency does not appear explicitly. It is actually included in the parent POM.

3

The plugin element is used to configure the Maven bundle plug-in.

There is no need to install the Maven bundle plug-in explicitly. Because the plug-in is archived in the default Maven2 repository (that is, http://repo1.maven.org/maven2/), Maven will automatically locate and download the plug-in the first time you build your application (provided that the build machine is connected to the Internet). The preceding configuration defines the following instructions for generating bundle headers:

<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
<Import-Package>*,org.apache.camel.osgi</Import-Package>
<Private-Package>org.apache.servicemix.examples.camel</Private-Package>

The preceding elements can be explained as follows:

Bundle-SymbolicName

Generates the Bundle-SymbolicName: manifest entry. In this example, it is set to the project's artifact ID, which resolves to camel-osgi. If you want to be sure to avoid a name clash, you could define the symbolic name as follows:

<Bundle-SymbolicName>$(pom.groupId).${pom.artifactId}</Bundle-SymbolicName>

Which would resolve to org.apache.servicemix.examples.camel-osgi in the current example.

Import-Package

Generates the Import-Package: manifest entry. The wildcard character , *, generates a list containing every referenced Java package not included in the current Maven project. The org.apache.camel.osgi package is listed explicitly, because it is not referenced in the source code, but it is needed at run time.

Private-Package

Generates the Private-Package: manifest entry. This entry does not correspond to a bundle header and is ignored by the OSGi container. The private package list contains the names of all the Java packages that are defined in the current bundle, but are not visible to other bundles. It is provided for information purposes only.

Because the bundle plug-in generates sensible defaults for most of the bundle headers, the preceding plug-in configuration is normally adequate to get you started with most projects. For more details about configuring the Maven bundle plug-in, see Maven bundle plug-in.