Petals-SE-Camel 1.0.0+

Features

The component SE Camel embeds the Apache Camel routing engine to execute enterprise integration patterns (EIP) in Petals.

Service Units can be written to describe, for a given provided Petals endpoint, how and where messages should be routed.

Even if it is recommended to route messages toward other Petals services, it is still always possible to exploit Camel transports to integrate with non-Petals external services.

This version must be installed on Petals ESB 5.0.0+
Contributors
No contributors found for: authors on selected page(s)

Introduction

This implementation of the SE Camel uses Camel version 2.15.3.

Routes can be defined using any of the JVM based DSL, as well as using the XML notation.
A Camel route always starts with a from declaration, a consumer, and often ends with one or many to declaration, producers.
Consumers and producers refers to service external to Camel using an URI: Petals services have their own URI scheme identified with petals.

For each provides section, exactly one route must be present and will be activated when a message is received.
Each route can call any service declared in a consumes section.

Consumes corresponds to an operation of a service and have a MEP defined.
Provides corresponds to a service defined with WSDL and for which every operation has one corresponding route.

The terminology used by Camel is apparently counter-intuitive to the one used in JBI terminology: a camel route consumes a service while an SU provides this same service.
This is because from the route point of view, messages arriving to the provided service are then consumed by the rule.
The SOA terminology is sometimes confusing: in the following we will use the general term service and operation interchangeably.

We show in the next section a general overview of a typical Camel Service Unit.

Overview of a Camel Service Unit at Runtime

Each SU has its own Camel context: the Camel context is the runtime entity responsible of executing the routes.
Routes in the same context can refer to each others when needed.

When a JBI exchange arrives for a provided service (an operation), it is transformed to a Camel exchange and dispatched to the route with a petals consumer (in the Camel terminology, i.e. with a from declaration using the petals URI scheme) the service.

When a Camel exchange is dispatched in a route to a petals producer (in the Camel terminology, i.e. with a to declaration using the petals URI scheme), it is transformed to a Petals exchange and sent to the corresponding consumes service.

For details on the transformation, see the section Petals to Camel to Petals below.

Overview of a Camel Service Unit at Implementation Time

Maven Project

When developing with Maven, the pom.xml file must contains the following kind of declarations:

<!-- ... -->

   <!-- We are producing a service unit -->
   <groupId>my.group</groupId>
   <artifactId>my-service-unit</artifactId>
   <version>1.0.0</version>
   <packaging>jbi-service-unit</packaging>

<!-- ... -->

   <dependencies>
      <!-- First a jbi-component dependency to the component (note that it won't provide anything in the classpath!) -->
      <dependency>
         <groupId>org.ow2.petals</groupId>
         <artifactId>petals-se-camel</artifactId>
         <version>1.0.0-SNAPSHOT</version>
         <type>jbi-component</type>
      </dependency>
      <!-- Then a dependency to camel, only if you plan to implement routes in Java -->
      <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-core</artifactId>
         <version>2.12.3</version>
         <!-- camel-core is provided by the component! -->
         <scope>provided</scope>
      </dependency>
      <!-- Maybe other dependencies if you relies on other camel extensions (for xml and java routes).
           Note: these extensions are NOT provided by the component and must thus be present with the (default) scope compile. -->
   </dependencies>

<!-- ... -->

   <build>
      <!-- Finally the petals maven plugins to generate JBI zip files -->
      <plugins>
         <plugin>
            <groupId>org.ow2.petals</groupId>
            <artifactId>maven-petals-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

<!-- ... -->

The project structure will follow typical maven projects :

my-service-unit/
  + pom.xml
  + src/
    + main/
    + jbi/
      + jbi.xml
      + service.wsdl (none, one or several)
    + java/.../MyRoutes.java (none, one or several)
    + resources/myroutes.xml (none, one or several)

On top of the typical pom.xml, there must be at least one route implementation per operation of the provides, in a jar file or an xml file, a WSDL description for every provides service of the JBI descriptor and of course a JBI descriptor.

Service Unit Content

A Camel SU generated from the previous Maven projects, named my-service-unit-1.0.0.zip will contains the following elements:

my-service-unit-1.0.0.zip
  + META-INF/
    + jbi.xml
  + service.wsdl (none, one or several)
  + my-service-unit-1.0.0.jar

Note that the jar is the generated Jar Maven artefact, and it is included in the generated Zip artefact by the petals maven plugin.

A Camel Route

Here is an example of a Camel route defined in XML:

  <!-- we must use the http://camel.apache.org/schema/spring namespace so Camel can load the routes
       but Spring JARs are not required -->
  <routes xmlns="http://camel.apache.org/schema/spring">
    <route>
      <from uri="petals:incomingOrders" />
      <convertBodyTo type="java.lang.String" />
      <choice>
        <when>
          <simple>${body} contains '?xml'</simple>
          <unmarshal>
            <jaxb contextPath="org.fusesource.camel" />
          </unmarshal>
          <to uri="petals:orders" />
        </when>
        <otherwise>
          <unmarshal>
            <bindy packages="org.fusesource.camel" type="Csv" />
          </unmarshal>
          <to uri="petals:orders2" />
        </otherwise>
      </choice>
    </route>
  <routes>

TODO. make that a real example...

The only specificity for Petals of this route are the URIs used to identify the services consumed by the route (from element) and to which messages are then sent (to element).
The scheme reserved to petals is petals: it is followed by : and then the unique id identifying a service's operation.

The rest is typical Camel but some Camel processors are particularly useful to handle Petals exchange from within Camel, such as the jaxb marshaller/unmarshaller or the body conversion.
See the section Camel Routes below for details.

JBI Descriptor and WSDL definition

The JBI descriptor contains:

  • The services that are provided by this SU for which routes will handle messages, and
  • The services consumed by this SU that will be callable from the route.

In order to identify a service's operation, each of the operation, provided or consumed, must have a unique id.
Of course, a provided service will be only usable by from elements and consumed services by to elements.

<?xml version="1.0" encoding="UTF-8"?>
<jbi:jbi version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jbi="http://java.sun.com/xml/ns/jbi"
   xmlns:petalsCDK="http://petals.ow2.org/components/extensions/version-5" xmlns:petals-se-camel="http://petals.ow2.org/components/petals-se-camel/jbi/version-1.0"
   xmlns:hello="http://petals.ow2.org">

   <jbi:services binding-component="false">

      <jbi:provides interface-name="hello:HelloInterface" service-name="hello:HelloService" endpoint-name="autogenerate">
         <petalsCDK:wsdl>service.wsdl</petalsCDK:wsdl>
      </jbi:provides>

      <jbi:consumes interface-name="hello:HelloInterface" service-name="hello:HelloService">

         <!-- Mandatory CDK specific elements -->
         <petalsCDK:operation>hello:sayHello</petalsCDK:operation>
         <petalsCDK:mep>InOut</petalsCDK:mep>

         <!-- Mandatory Component specific elements -->
         <petals-se-camel:service-id>theConsumesId</petals-se-camel:service-id>
      </jbi:consumes>

      <!-- These are found in the jar packaged by Maven and included in the JBI Zip -->
      <petals-se-camel:xml-routes>routes.xml</petals-se-camel:xml-routes>
      <petals-se-camel:java-routes>org.test.ASimpleRoute</petals-se-camel:java-routes>

   </jbi:services>
</jbi:jbi>
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://petals.ow2.org" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
   xmlns:tns="http://petals.ow2.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:petals-camel-wsdl="http://petals.ow2.org/components/petals-se-camel/wsdl/version-1.0">
   <wsdl:types>
      <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://petals.ow2.org"
         elementFormDefault="unqualified" targetNamespace="http://petals.ow2.org" version="1.0">
         <xs:element name="sayHello" type="tns:sayHello" />
         <xs:element name="sayHelloResponse" type="tns:sayHelloResponse" />
         <xs:complexType name="sayHello">
            <xs:sequence>
               <xs:element minOccurs="0" name="arg0" type="xs:string" />
            </xs:sequence>
         </xs:complexType>
         <xs:complexType name="sayHelloResponse">
            <xs:sequence>
               <xs:element minOccurs="0" name="return" type="xs:string" />
            </xs:sequence>
         </xs:complexType>
      </xs:schema>
   </wsdl:types>
   <wsdl:message name="sayHelloResponse">
      <wsdl:part name="parameters" element="tns:sayHelloResponse" />
   </wsdl:message>
   <wsdl:message name="sayHello">
      <wsdl:part name="parameters" element="tns:sayHello" />
   </wsdl:message>
   <wsdl:portType name="HelloInterface">
      <wsdl:operation name="sayHello">
         <wsdl:input name="sayHello" message="tns:sayHello" />
         <wsdl:output name="sayHelloResponse" message="tns:sayHelloResponse" />
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name="HelloServiceBinding" type="tns:HelloInterface">
      <wsdl:operation name="sayHello">
         <petals-camel-wsdl:operation service-id="theProvidesId" />
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="HelloService">
      <wsdl:port name="autogenerate" binding="tns:HelloServiceBinding" />
   </wsdl:service>
</wsdl:definitions>

In these two snippets, the important parts are the elements with the namespace URI http://petals.ow2.org/components/petals-se-camel/jbi/version-1.0 for the JBI and http://petals.ow2.org/components/petals-se-camel/wsdl/version-1.0 for the WSDL.

The first one enables to define the service id for a consumes in the JBI: notice that the consumes must also have a MEP (or a default one (imposed by the Camel SE) is used, that is InOut) and an operation set.

The second one enables to define the service id for the operation of a provides in the binding section of the WSDL definition: again the operation must have an MEP set (or the default one (imposed by the WSDL specification) is used, that is Inout).

Finally, the services section of the JBI contains a list of routes to be loaded by the Camel SE.
Two types of route definitions can be used: java classes and XML files.
Java classes refer to classes that extends the Camel RouteBuilder abstract class, i.e. routes written with any of the JVM-based DSLs: Camel DSL Page.
XML files refer to routes defined used the XML DSL from Camel: Camel XML Examples.

Semantics of the Send operation (synchronicity, timeouts, etc)

By default, the execution is asynchronous: it means that if one of the processor or producer on the route needs to do blocking operations, the processing won't keep the CDK thread that received the message busy and it will continue execution when it is time to depending on the blocked processor.
This has no impact on how the routes are implemented, but in term of execution, it means that threads are not blocked and resources are often freed as soon as possible.
See Camel Asynchronous Routing Engine and Camel Asynchronous Processing for technical details.

Nevertheless, it is possible to force synchronous execution:

  • of a whole route either by adding the synchronous argument to the Camel from URI, or
  • of a service invocation when calling an external petals services using a to with the same argument.

It is also possible to have a timeout (both for synchronous and asynchronous mode) to specify how long we should wait before failing a service invocation done with to by using the timeout option.
Note: by default, it will use the value specified in the JBI consumes section and as usual, the value 0 means no timeout.

Petals to Camel to Petals

Petals (i.e. JBI) and Camel share many concepts to format exchanges.
They both have exchanges with a WSDL MEP, In, Out and Fault messages, as well as Errors.
The main difference is that Camel exchanges do not make mandatory the use of XML for the messages content and that they have no explicit status (the status of Camel exchange is inferred from their content).

An error seems to be present in Camel: the InOptionalOut MEP has the wrong URI (ending with in-optional-out instead of in-opt-out according to the WSDL specification).
Note: this will be fixed in Camel 2.16.x and will most certainly be included in version 1.0.0 of the SE.

From Petals to Camel

When a new exchange arrives on a provides endpoint, the following happen:

The JBI exchange is transformed to a Camel exchange.
Its properties are put into the Camel exchange properties (by reference).
Its In normalized message is transformed to a Camel message.
Its properties are put into the Camel message headers (by reference).
Its attachments are put into the Camel message attachments (by reference).
The content of the normalized message (a Source object in Java, containing XML) is put in the body of the Camel message without change.

From Camel to Petals

When an exchange is sent from Camel to Petals through a consumes endpoint, the following happen:

The Camel exchange is transformed to a JBI exchange.
Its properties are put into the JBI exchange properties (by reference).
Its In message is transformed to a normalized message.
Its headers are put into the normalized exchange properties (by reference).
Its attachments are put into the normalized message attachments (by reference).
The body is transformed, using available Camel type converters, to a DOMSource object (or if it is already a Source, it stays as a Source) and put in the content of the normalized message.

Back to Camel from Petals

When an answer to an exchange sent to Petals arrives back to Camel through a consumes endpoint, the following happen:

If the exchange has the error status, the exception is put in the exchange.
If the exchange has a Fault, it is transformed to a Camel message (same process as before), the fault status is set on it and put as the exchange's Out.
If the exchange has an Out, it is transformed to a Camel message (same process as before) and put as the exchange's Out.

Back to Petals from Camel

When an answer to an exchange sent to Camel from Petals arrives back to Petals through a provides endpoint, the following happen:

If the exchange has an Exception, the exception is put as the JBI exchange's error and its status is set to error.
If the exchange has a Fault, it is transformed to a normalized message of type fault (same process as before) and put as the JBI exchange's Fault.
If the exchange has an Out and it is an InOut or an InOptionalOut, it is transformed to a normalized message (same process as before) and put as the JBI exchange's Out.
If the exchange has no Out and it is an InOut exchange, its In message is transformed to a normalized message (same process as before) and put as the JBI exchange's Out.
In all the other cases, the exchange's status is changed to done.

Some Camel processors are made to work in-place with an In message without making an Out message: because of this practice (see http://camel.apache.org/using-getin-or-getout-methods-on-exchange.html), we have to make the assumption that an InOptionalOut Camel message MUST have an Out message for the exchange to be considered not done!
In other words: before sending an InOptionalOut message that has an Out message back to Petals, make sure that the answer is not in the In but in the Out message of the Camel exchange.

Examples

Some examples are available with the SE.
In particular, the example named su-camel-databinding shows how to do some logging as well as convert the body of the JBI messages to Java objects using JAXB.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.