...
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.
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.
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:
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 |
---|
|
<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>
|
Static configuration
When used in a static configuration, beans can be automatically discovered amongst spring configured 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
.
MessageExchangeListener
The first kind of POJOs you can deploy implement the MessageExchagneListener
interface. In such a case, servicemix-bean
acts as a replacement of the lightweight container component. This level offers the most control on the exchange received and sent. This is usually used with the injected DeliveryChannel
to send back the exchanges, or if the POJOs needs to act as a consumer (i.e. creating and sending exchanges to other services).
These POJOs are low-level POJOs: you need to understand the JBI Api and Message Exchange Patterns to correctly handle incoming exchanges.
Note that at this point (v 3.1), there is no base class that you can inherit to speed you in this process of implementing a POJO to handle JBI exchanges, but hopefully it will come in the future.
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 |
---|
lang | java |
---|
title | Trace 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); |
|
|
Code Block |
---|
|
<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>
exchange.setStatus(ExchangeStatus.DONE);
|
| </sm:activationSpec></sm:activationSpecs>
</sm:container>
<bean id="consumerBean" class="org.apache.servicemix.bean.beans.ConsumerBean"/>
<bean id="listenerBean" class=" |
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 |
---|
lang | java |
---|
title | Echo example |
---|
|
import org.apache.servicemix. |
| beanbeans.ListenerBean"/>
<bean id="annotatedBean" class="listener.MessageExchangeListener;
import org.apache.servicemix. |
| beanbeans.AnnotatedBean"/>
<bean id="plainBean" class="org.apache.servicemix.bean.beans.PlainBean"/>
</beans>
|
Such beans can be accessed by resolving a URI:
Code Block |
---|
|
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 |
---|
|
<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>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 {
|
| <sm:activationSpec>
if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
|
| <sm:component>
<bean:component searchPackages="org.apache.servicemix.bean.beans"/>
MessageUtil.transferInToOut(exchange, exchange);
|
| </sm:component></sm:activationSpec>
</sm:activationSpecs>
</sm:container></beans>
|
In such a case, beans must have the @Endpoint
annotation.
...
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. |
| xmljava | title | Message processing example |
---|
|
|
| <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>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 |
| <bean:component>
(exchange.getStatus() == ExchangeStatus.ACTIVE) {
|
| <bean:endpoints>
<bean:endpoint service="test:service" endpoint="endpoint" bean="#listenerBean">
NormalizedMessage message = exchange.getMessage("in");
Source content = |
| </bean:endpoints>
<bean:component>
</sm:component>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);
|
| </sm:activationSpec></sm:activationSpecs>
</sm:container>
<bean id="listenerBean" class="org.apache.servicemix.bean.beans.ListenerBean"/>
</beans>
|
...
Disclaimer
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.
MessageExchange dispatching
If the POJO deployed implements the org.apache.servicemix.MessageExchangeListener
, every message received for this POJO will be dispatched to the onMessageExchange
method.
In other cases, exchanges in a provider role will be dispatched according to the MethodInvocationStrategy
configured on the endpoint. The default one try to find the method according to the operation name defined on the exchange. If there is only a single method acting as an operation, it will always be used.
Annotations
The servicemix-bean
component can accept different kind of POJOs. These POJOs may be annotated to customize their behavior. All the following annotations belong to the org.apache.servicemix.bean
package.
...
Annotation | Target | Description |
---|
Resource | Field | The Resource annotation marks a resource that is needed by the application. Currently, this annotation is only supported on fields of type ComponentContext and DeliveryChannel . The component will inject the specified resource when the POJO is instantiated. |
PostConstruct | Method | The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. |
PreDestroy | Method | The PreDestroy annotation is used on methods as a callback notification to signal that the instance is in the process of being removed by the container. |
The following interfaces are part of this API:
Interface | Description |
---|
MessageExchangeListener | When the POJO implements this interface, all exchanges will be dispatched to the onMessageExchange method. |
Destination | This interface can be used to define a property on the bean, annotated with the @ExchangeTarget annotation. This is a very simple API to send exchanges from a POJO. More complex use cases can use an injected DeliveryChannel directly or to create a ServiceMix client. |
Examples
URI
You can use a handy URI to refer to beans using the Spring names of beans.
...