Thursday, August 30, 2018

Oracle SOA: Sending delayed JMS messages

Sometimes you might want to put something on a JMS queue and make it available after a certain period has passed to consumers. How can you achieve this using Oracle SOA Suite?

Queue or connection factory configuration. Works but not message specific

You can set the Time-to-Deliver on the queue or on the connection factory. This indicates a period during which the message is visible in the WebLogic console but will not be seen by consumers (they will have state 'delayed').
  • Queue overrides
    • On queue level you can configure a Time-to-Deliver override. This will delay all messages which are being send to the queue. In this case however, we wanted to tweak the delay per message.
  • Connection Factory
    • On connection factory level you can configure the default Time-to-Deliver. This delay will be given by default to all messages using the specific connection factory. If you want to use multiple delays on the same queue you can connect to it using multiple connection factories. This again is configuration which is not message specific
JMSAdapter. Sending delayed messages is not possible

Producing delayed messages can be done by calling relevant Java classes (dependent on your JMS implementation) such as described here. When implementing Oracle SOA solutions however, it is more common to use the JMSAdapter instead of directly calling Java code.With the JMSAdapter you can set and get specific JMS header properties. See for example here.
  • JMSProperties
    • At first I tried to set the JMS header DeliveryTime. This header however is calculated when a message is produced to a queue or topic.I could not set this property externally
    • I also tried the property JMS_OracleDelay which can be used with the Oracle AQ JMS implementation. This also did not work with a JMS implementation which used a JDBC persistent store.
By setting specific JMS properties using the JMSAdapter, I did not manage to get this working. Maybe there was some other way using the JMSAdapter? I discovered the JMSAdapter does not call the relevant Java method to produce delayed messages (a feature the AQAdapter does provide). The JMSAdapter thus could not be used to achieve the required functionality. The method which needed to be called was: setTimeToDeliver on the weblogic.jms.extensions.WLMessageProducer.

Consuming messages

Using the JMSAdapter however, we can pick-up delayed messages. A benefit of using the JMSAdapter is that you can easily configure threads (even singleton over a clustered environment) and the delay between messages which are consumed. See for example the below snipplet from the composite.xml;

    <binding.jca config="MyServiceInboundQueue_jms.jca">
    <property name="minimumDelayBetweenMessages">10000</property>
    <property name="singleton">true</property>
    </binding.jca>

This makes sure only one message every 10 seconds is picked up from the queue.

BPEL Java embedding. Producing JMS messages without extending the BPEL engine classpath is not possible

Oracle SOA BPEL provides a feature to embed Java code. We thought we could use this Java code to produce JMS messages with delay since when using Java, we could call the required method. It appeared however that the classpath which was used by the BPEL engine was limited. Classes like javax.jms.* were not available. We could add additional libraries by configuring the BpelcClasspath property in the System MBean Browser to make these standard J2EE libraries available. See here. We did not want to do this however since this would make automatic deployment more challenging and we were unsure we would not introduce side-effects..

Spring component

It appeared the classpath which was available from the Spring component did contain javax.jms.* classes! We did fear however that the context in which the Spring component would run could potentially make it difficult to access the relevant connection factory and queue. Luckily this did not appear to be an issue. Additional benefit of using the Spring component is encapsulation of the Java code and better maintainability. Also in the BPEL process the callout to the Java code was more explicitely visible in form of an invoke.

In order to create a Spring component, the following needs to be done. See for a more elaborate example here.
  • Create a JDeveloper Java project with a library as dependency which contained the javax.jms.* classes such as 'JAX-WS Web Services'. For SOA Suite 11g make sure you indicate the Java SE version is 1.6. Create a deployment profile to be able to package the code as a JAR file.
  • Implement the Java code to put a message on the queue. See for example here and create a JAR file from it by compiling the code.
  • For JDeveloper 11g make sure the Oracle JDeveloper Spring, WebLogic SCA Integration plugin is installed.
  • Copy the previously created JAR file to your composite project folder subdirectory SCA-INF/lib
  • In the composite editor create a Spring component. Add XML code like for example below
  • The Spring component will display an interface. Drag it to the BPEL process where you want to use it. An XSD/WSDL will be generated for you and you can use an assign and invoke to call this service. If you update the interface file / replace the JAR file, you can remove the Spring component interface, add it again to the bean definition xml file, re-wire it to the BPEL component and it will regenerate the WSDL and XSD files.
Summary

  • The JMSAdapter does not allow enqueueing messages with a specific delay (time-to-deliver).
  • A (default) time-to-deliver (delay) can be configured on the queue but also on the connection factories
  • The Spring component uses a different classpath than Java embedded in BPEL
  • The Spring component can access the InitialContext which in turn allows access to WebLogics JNDI tree
  • Using the Spring component it is relatively easy to enqueue messages with a message specific delay

No comments:

Post a Comment