A JMS provider can be used as the transport for one-way and request-response operations. A minimal one-way configuration is shown below:
<component name="OneWayClient"> <implementation.java class="..."/> <reference name="service"> <binding.jms> <destination jndiName="serviceQueue"/> </binding.jms> </reference> </component> <component name="OneWayService"> <implementation.java class="..."/> <service> <binding.jms> <destination jndiName="serviceQueue"/> </binding.jms> </service> </component>
The above configuration uses the "serviceQueue" queue to propagate messages. Depending on the JMS provider, it may also be necessary to specify a connection factory name (see below).
Non-Blocking Operations
When writing asynchronous Java components, it is important to remember the @OneWay annotation. If a method is not marked with @OneWay, it will be taken as a request-response operation even if the return value is void. This means the operation will block until a response message is received.
Configuring request-response operations involves specifying a separate response queue in addition to the forward queue:
<component name="RequestResponseClient"> <implementation.java class="..."/> <reference name="service"> <binding.jms> <destination name="serviceQueue"/> <response> <destination jndiName="responseQueue"/> </response> </binding.jms> </reference> </component> <component name="RequestResponseService"> <implementation.java class="..."/> <service> <binding.jms> <destination name="serviceQueue"/> <response> <destination jndiName="responseQueue"/> </response> </binding.jms> </service> </component>
Using Callbacks
While JMS is an asynchronous model, it is important to note that the client component will block on request-response operations until a response is received. In some cases, this is the desired behavior. In other situations, such as long-running interactions, looser coupling is required where the client can continue processing without waiting for a response to be returned. Callbacks can be used to provide responses at some later point in time. Configuring callbacks involves specifying a callback queue:
<component name="CallbackClient"> <implementation.java class="..."/> <reference name="service"> <binding.jms> <destination name="serviceQueue"/> </binding.jms> <callback> <binding.jms> <destination name="callbackQueue"/> </binding.jms> </callback> </reference> </component> <component name="CallbackService"> <implementation.java class="..."/> <service> <binding.jms> <destination name="serviceQueue"/> </binding.jms> <callback> <binding.jms> <destination name="callbackQueue"/> </binding.jms> </callback> </service> </component>
When the CallbackClient invokes the CallbackService, the call will return immediately. At some later point in time, a reponse will be delivered asynchronously using the "callbackQueue" queue.
Specifying Connection Factories
The previous examples assumed the JMS provider did not require the connection factory to be specified for simplicity. However, most JMS providers will require the connection factory to be specified using the conectionFactory element:
<component name="CallbackClient"> <implementation.java class="..."/> <reference name="service"> <binding.jms> <connectionFactory jndiName="TheConnectionFactory"/> <destination name="serviceQueue"/> </binding.jms> </reference> </component>
Dynamically Creating Queues
The JMS binding can also be configured to create queues dynamically by using the create attribute on the destination element and setting it to "ifnotexist" or "always".
Queues vs. Topics
By default, the JMS binding uses Queues to reference and service bindings. While it is possible to specify a Topic using the type="topic" attribute on the destination element, this should be avoided as doing so may have unintended effects. Specifically, if a service is clustered and bound to a topic, all service replicas in the zone will receive copies of an invocation message. With Queues, only one clustered service replica will receive a copy, which is in most cases the correct behavior for service interactions.
Wire Formats
The JMS binding supports multiple wire formats including object serialization, JMS message types, and JAXB serialization. If a parameter type is annotated with the JAXB @XmlRootElement annotation, parameters will be sent as XML using a JMS text message. Otherwise, the JMS binding will introspect the parameter types and select the most appropriate message type (e.g. object, bytes, etc).
Transacted Messaging
Fabric3 supports XA transacted messaging. This is useful when a message must be reliably sent in conjunction with a database update. To enable transacted messaging, use the transactedOneWay intent on the JMS binding:
<component name="TheComponent"> <implementation.java class="..."/> <reference name="service"> <binding.jms requires="transactedOneWay"> <destination jndiName="TheQueue"/> </binding.jms> </reference> </component>
The above will enqueue a message transactionally with the message provider. The component implementation is as follows:
public class TheComponent implements ... { @Reference protected Service service; public void operation() { Message message = ... service.invoke(message); } }
If the above implementation also needed to update a database using Hibernate in the same transaction as the message enque, it could be modified as follows to use the @ManagedTransaction annotation:
@ManagedTransaction public class TheComponent implements ... { @PersisitenceContext(unitName = "employee") Session session; @Reference protected Service service; public void operation() { Message message = ... long id = message.getId(); Entity entity = session.find(Entity.class, id); entity.update(message.getUpdate()); service.invoke(message); } }
Transacted Messaging and Request-Response
In a word: don't try it. Transacted messaging will not work with request reply. To see why, consider the following:
@ManagedTransaction public class TheComponent implements ... { @Reference protected Service service; public void operation() { Message message = ... Response response = service.invoke(message); } }
The forward transaction will not commit until after the response is received and the operation() method has returned. However, the outgoing message will not be enqueued until the transaction commits. This means that the message can not be sent and consequently a response will never be received. The result will be a message timeout.
<component name="AsyncClientService"> <implementation.java class="..."/> <reference name="service"> <binding.jms requires="transactedOneWay"> <destination jndiName="TheQueue"/> </binding.jms> <callback> <binding.jms requires="transactedOneWay"> <destination jndiName="asyncClientServiceCallbackQueue"/> </binding.jms> </callback> </reference> </component>
---> don't use request response --> onl one way
Service Auto Scaling
Fabric3 supports autoscaling where the number of message listeners for a service endpoint are dynamically resized based on workload. The following are the autoscaling attributes which can be configured per endpoint as attributes on binding.jms:
idle.limit
transaction.timout
receive.timeout
max.messages
recovery.interval
max.receivers
min.receivers
Add Comment