Java CAPS Tip: Simple JMS Message Routing

The following article describes a simple, JMS based, dynamic messaging routing solution using the Sun Java CAPS suite. Although the example if simple it is also scalable and works in all the environments I have used. The primary reason for this blog is so that I can describe in a future blog how to implement this using the new Java CAPS 6 environment and what the key differences are. This said the solution described in this article will build and run within the Java CAPS 6 Classic environment.

Resources
Message Based Routing

The message based routing Java Collaboration (JCD) stores all its routing information within the "msgRouter.properties" file that must exist within the classpath for the server and the simplest solution to this is to place the file in the domains lib/classes directory. On first startup the JCD will read the contents of the properties file into a local Properties variable, "msgRouterProperties", which it will query later in the code to identify the required destination. This particular example will route the messages based on a JMS User property and hence does not need to know anything about the message structure or content. I would recommend that this structure always be used and if you require message based routing then add another JCD that unmarshals the message and sets the appropriate JMS property then passes then messages onto the Routing JCDs inbound queue.

You can see from the code below that the JCD initially obtains the default Message Server and Queue name to be used in the event that the routing property value can not be found in the properties file. If the default properties are not found within the properties file then the JCD will default to the Message Server and Queue Name defined in the Connectivity Map and Deployment profile.

The JCD will then attempt to obtain the Message Routing Property (TPPROPERTY) and subsequently the specific Message Server and Queue name matching that property:
  • Message Server : <Routing Value>.msgServerURL
  • Queue Name : <Routing Value>.queueName
Once these values have been obtained or the default values used if they do not exist then the outbound JMS Connections Message Server URL is set and the message is sent to the appropriate destination. The actual destination type, Queue or Topic, is set within the Connectivity Map. Once the message has been sent then the connection URL is reset to the default value for the next invocation.

JCD Code

public class jcdMsgRouter
{

    public com.stc.codegen.logger.Logger logger;

    public com.stc.codegen.alerter.Alerter alerter;

    public com.stc.codegen.util.CollaborationContext collabContext;

    public com.stc.codegen.util.TypeConverter typeConverter;

    private static final java.util.Properties msgRouterProperties = new java.util.Properties();

    private static final String TPPROPERTY = "TRADING-PARTNER";

    public void receive( com.stc.connectors.jms.Message input, com.stc.connectors.jms.JMS jmsOut )
        throws Throwable
    {
        String msgServerURL = null;
        String queueName = null;
        String tpName = null;
        String defaultMsgServerURL = null;
        String defaultQueueName = null;
        try {
            // Load Properties if required
            if (msgRouterProperties.isEmpty()) {
                java.io.InputStream propIS = this.getClass().getClassLoader().getResourceAsStream( "msgRouter.properties" );
                if (propIS != null) {
                    msgRouterProperties.load( propIS );
                    logger.info( "\*\*\* APH-I1 : Loading msgRouter.properties" );
                } else {
                    logger.info( "\*\*\* APH-I2 : Can not find msgRouter.properties" );
                }
            }
            // Trading Partner Message Property
            for (int i1 = 0; i1 < input.countUserProperty(); i1 += 1) {
                if (TPPROPERTY.equals( input.getUserProperty( i1 ).getName() )) {
                    tpName = (String) input.getUserProperty( i1 ).getValue();
                    break;
                }
            }
            if (tpName != null && !msgRouterProperties.isEmpty()) {
                if (defaultMsgServerURL == null) {
                    defaultMsgServerURL = msgRouterProperties.getProperty( "default.msgServerURL" );
                    defaultQueueName = msgRouterProperties.getProperty( "default.queueName" );
                }
                msgServerURL = msgRouterProperties.getProperty( tpName + ".msgServerURL", defaultMsgServerURL );
                queueName = msgRouterProperties.getProperty( tpName + ".queueName", defaultQueueName );
                // Log
                logger.info( "\*\*\* APH-I1 : msgServerURL = " + msgServerURL );
                logger.info( "\*\*\* APH-I1 : queueName = " + queueName );
                // Set JMS Params
                if (msgServerURL != null) {
                    if (defaultMsgServerURL == null) {
                        defaultMsgServerURL = jmsOut.getMessageServerURL();
                    }
                    jmsOut.setMessageServerURL( msgServerURL );
                }
                if (queueName != null) {
                    jmsOut.sendTo( input, queueName );
                } else {
                    jmsOut.send( input );
                }
            } else {
                throw new Exception( "TP Name" + tpName + " does not exist or no valid properties" );
            }
        } catch ( Exception e ) {
            logger.warn( "\*\*\* APH-I3 : Failed to send message", e );
            if (msgServerURL != null && defaultMsgServerURL != null) {
                jmsOut.setMessageServerURL( defaultMsgServerURL );
            }
            jmsOut.sendTo( input, "TP_SEND_ERROR" );
        } finally {
            if (msgServerURL != null && defaultMsgServerURL != null && !msgServerURL.equals( defaultMsgServerURL )) {
                jmsOut.setMessageServerURL( defaultMsgServerURL );
            }
        }
    }
}

Properties File

default.msgServerURL=stcms://localhost:18007
default.queueName=qRouterOut
partner1.msgServerURL=stcms://localhost:19007
partner1.queueName=qPartner1
partner2.msgServerURL=stcms://localhost:18007
partner2.queueName=qPartner2


Comments:

It's nice to see that this is the same way as I am implementing a routing function :)

One question: why using 'jmsOut.sendTextTo' and 'jmsOut.sendText'? I use the plain 'send' and 'sentTo'. Doesn't the sendText put any constrains on the messsage (like being a text message)?

- Remold

Posted by Remold Krol on June 02, 2008 at 02:00 PM GMT #

Remold the reason I have sendTextTo is because the code was actually taken from an implementation where I new I would only have text messages. You are quite correct replacing it by a simple sendTo will make it more generic.

Posted by guest on June 03, 2008 at 02:02 AM GMT #

hi \*,

i would only recommend this functionality for CAPS 5.1.x users. afaik all other versions newer or older do not support this anymore or never have.

regards chris

Posted by Christian Brennsteiner on June 03, 2008 at 04:26 AM GMT #

Chris the setMessageServerURL was not available in ICAN 5.0.x but the sendTo was. I did specify CAPS 5.1.x because the 5.0.x release was known as ICAN.

Posted by guest on June 03, 2008 at 04:58 AM GMT #

what about 6.0? i think it has been declared as "deprecated" in 6.0

regards chris

Posted by Christian Brennsteiner on June 03, 2008 at 08:34 AM GMT #

This will work in the Java CAPS 6 environment but the main purpose of the Blog was so I could write one later that compares and contrasts how to implement similar functionality using the new features available in Java CAPS 6

Posted by guest on June 04, 2008 at 01:56 AM GMT #

What are the benefits of using the tip? Improve performance? Simply coding? Please advise. Thanks!

Posted by Cindy Vogel on August 29, 2008 at 08:57 AM GMT #

This simple method does provide improved performance because we can dynamically route messages around multiple message servers. In addition the routing functionality is kept within a single location (jcd)and hence the other components need only worry about implementing business functionality and then once complete pass the message on to the next stage. The example functionality implement with the entry has been used in association with the eXchange product to split the message delivery functionality onto separate domains. Because of the nature of the configuration it will allow additional trading partners to be added and they can either use an existing, low volume, delivery service or have their own created. This provide complete flexibility without having to recompile and redeploy.

Posted by guest on September 01, 2008 at 06:28 AM GMT #

Post a Comment:
Comments are closed for this entry.
About

As a member of the Oracle A-Team we specialise in enabling and supporting the Oracle Fusion Middleware communities.

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today