Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

The ServiceMix Bean component provides integration with beans (POJOs) with the JBI bus to make it easy to use POJOs to process JBI message exchanges. Like in an Message Driven Bean in J2EE a POJO will receive a message from the NMR and process it in any way it likes. Unlike in a JMS component where the coding is already done the Bean component gives the developer the freedom to create any type of message handling but it must be hand coded all the way.

Maven Archetype

You can simple create a bean SU (with a bean sample) using the servicemix-bean-service-unit archetype :

Code Block

mvn archetype:create \
  -DarchetypeGroupId=org.apache.servicemix.tooling \
  -DarchetypeArtifactId=servicemix-bean-service-unit \
  -DarchetypeVersion=2010.01 \
  -DgroupId=your.group.id \
  -DartifactId=your.artifact.id \
  -Dversion=your-version

Once you've customized the service unit, simply install the SU:

Code Block

mvn install
Info

Remember that to be deployable in ServiceMix, the ServiceUnit has to be embedded in a Service Assembly: only the Service Assembly zip file can be deployed in ServiceMix.
To add your SU in a SA, you need to define it in the dependency sets:

Code Block

<dependency>
  <groupId>your.group.id</groupId>
  <artifactId>your.artifact.id</artifactId>
  <version>your-version</version>
</dependency>

Endpoint Configuration

Code Block
xml
xml

<beans xmlns:bean="http://servicemix.apache.org/bean/1.0">

  <bean:endpoint service="test:service" endpoint="endpoint" bean="#listenerBean"/>

  <bean id="listenerBean" class="org.apache.servicemix.bean.beans.ListenerBean"/>

</beans>

Attention: The Bean Endpoint schema allows to set a Bean or a Bean Name. The Bean will create a single instance of the POJO per endpoint whereas the Bean Name will create an instance per request (message exchange).

POJOs

There are several kind of POJOs you can deploy to servicemix-bean.

...

Section
Column

This example on the right shows the most simple bean. When it receives an exchange, it will print it to the console and set the status to DONE before sending the exchange back.
This bean can not handle InOut exchanges, as it does not set any response (an exception would be thrown in such a case).

Column
Code Block
langjava
titleTrace example
import org.apache.servicemix.jbi.listener.MessageExchangeListener;

import javax.annotation.Resource;
import javax.jbi.messaging.DeliveryChannel;
import javax.jbi.messaging.ExchangeStatus;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;

public class ListenerBean implements MessageExchangeListener {

    @Resource
    private DeliveryChannel channel;

    public void onMessageExchange(MessageExchange exchange) throws MessagingException {
        System.out.println("Received exchange: " + exchange);
        exchange.setStatus(ExchangeStatus.DONE);
        channel.send(exchange);
    }

}
Section
Column

This example will handle an InOut exchange and will send back the input as the response.
Note that this example would fail if receiving an InOnly exchange, as setting a response on an InOnly exchange is not a legal operation.

Column
Code Block
langjava
titleEcho example
import org.apache.servicemix.jbi.listener.MessageExchangeListener;
import org.apache.servicemix.jbi.util.MessageUtil;

import javax.annotation.Resource;
import javax.jbi.messaging.DeliveryChannel;
import javax.jbi.messaging.ExchangeStatus;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;

public class ListenerBean implements MessageExchangeListener {

    @Resource
    private DeliveryChannel channel;

    public void onMessageExchange(MessageExchange exchange) throws MessagingException {
        if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
            MessageUtil.transferInToOut(exchange, exchange);
            channel.send(exchange);
        }
    }

}
Section
Column

This is similar example as the one from above (also works only for InOut exchange) but it shows how you can extract message from an exchange in order to process it and send back.

Column
Code Block
langjava
titleMessage processing example
import org.apache.servicemix.jbi.listener.MessageExchangeListener;
import org.apache.servicemix.jbi.util.MessageUtil;
import org.apache.servicemix.jbi.jaxp.SourceTransformer;

import javax.annotation.Resource;
import javax.jbi.messaging.DeliveryChannel;
import javax.jbi.messaging.ExchangeStatus;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;
import javax.xml.transform.Source;

public class ListenerBean implements MessageExchangeListener {

    @Resource
    private DeliveryChannel channel;

    public void onMessageExchange(MessageExchange exchange) throws MessagingException {
        if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
                        NormalizedMessage message = exchange.getMessage("in");
		        Source content = message.getContent();
			//process content according to your logic
			//e.g. to access the message body as a String use
			String body = (new SourceTransformer()).toString(content);

			message.setContent(content);
			exchange.setMessage(message, "out");
			channel.send(exchange);
        }
    }

}

...

In versions 3.1 to 3.1.2 the ServiceMix Bean component will not handle asynchronous messages correctly because the final send of the message marked as DONE back to the NMR will be handled as a consumer message and that fails because there is no corresponding provider message. The only workaround is to send the messages synchronously.

Note: This was resolved in 3.1.3, 3.2.x and later via SM-1110.

Deployment

Currently (v 3.1), servicemix-bean supports two different deployment models. The first one uses an xbean.xml configuration file where one can configure the different endpoints / beans that will be used. The other one only works with a static configuration file (servicemix.xml) and can not be used with standard JBI packaging but allows automatic detection of the beans to expose.

xbean.xml

...


<beans xmlns:bean="http://servicemix.apache.org/bean/1.0">

  <bean:endpoint service="test:service" endpoint="endpoint" bean="#listenerBean"/>

  <bean id="listenerBean" class="org.apache.servicemix.bean.beans.ListenerBean"/>

</beans>

Attention: The Bean Endpoint schema allows to set a Bean or a Bean Name. The Bean will create a single instance of the POJO per endpoint whereas the Bean Name will create an instance per request (message exchange).

Static configuration

When used in a static configuration, beans can be automatically discovered amongst spring configured beans:

Code Block
langxml

<beans xmlns:sm="http://servicemix.apache.org/config/1.0"
       xmlns:bean="http://servicemix.apache.org/bean/1.0"
       xmlns:test="urn:test">

  <sm:container id="jbi" embedded="true" createMBeanServer="false">
    <sm:activationSpecs>
      <sm:activationSpec>
        <sm:component>
          <bean:component/>
        </sm:component>
      </sm:activationSpec>
    </sm:activationSpecs>
  </sm:container>

  <bean id="consumerBean" class="org.apache.servicemix.bean.beans.ConsumerBean"/>
  <bean id="listenerBean" class="org.apache.servicemix.bean.beans.ListenerBean"/>
  <bean id="annotatedBean" class="org.apache.servicemix.bean.beans.AnnotatedBean"/>
  <bean id="plainBean" class="org.apache.servicemix.bean.beans.PlainBean"/>

</beans>

Such beans can be accessed by resolving a URI:

Code Block
langjava

DocumentFragment epr = URIResolver.createWSAEPR("bean:annotatedBean");
ServiceEndpoint se = client.getContext().resolveEndpointReference(epr);
exchange.setEndpoint(se);

Beans can also be discovered by searching within defined packages:

Code Block
langxml

<beans xmlns:sm="http://servicemix.apache.org/config/1.0"
       xmlns:bean="http://servicemix.apache.org/bean/1.0"
       xmlns:test="urn:test">

  <sm:container id="jbi" embedded="true" createMBeanServer="false">
    <sm:activationSpecs>
      <sm:activationSpec>
        <sm:component>
          <bean:component searchPackages="org.apache.servicemix.bean.beans"/>
        </sm:component>
      </sm:activationSpec>
    </sm:activationSpecs>
  </sm:container>

</beans>

In such a case, beans must have the @Endpoint annotation.

Of course, you can use the endpoint xml element to configure your POJOs:

Code Block
langxml

<beans xmlns:sm="http://servicemix.apache.org/config/1.0"
       xmlns:bean="http://servicemix.apache.org/bean/1.0"
       xmlns:test="urn:test">

  <sm:container id="jbi" embedded="true" createMBeanServer="false">
    <sm:activationSpecs>
      <sm:activationSpec>
        <sm:component>
          <bean:component>
            <bean:endpoints>
              <bean:endpoint service="test:service" endpoint="endpoint" bean="#listenerBean"/>
            </bean:endpoints>
          </bean:component>
        </sm:component>
      </sm:activationSpec>
    </sm:activationSpecs>
  </sm:container>

  <bean id="listenerBean" class="org.apache.servicemix.bean.beans.ListenerBean"/>

</beans>

Note: Please make sure that the namespace specified at the top xmlns:test does match to the namespace used in the endpoint's service test:service. When calling the service by the service name then you need to add the namespace in order to find the service like {urn:test}service.

MessageExchange dispatching

...