Getting started with simple correlator-integrated messaging for JMS

This section describes the steps for creating an Apama application that uses correlator-integrated messaging for JMS where guaranteed delivery is not required. Apama provides an example application in Apama Plugin for Eclipse that illustrates a simple use of correlator-integrated messaging for JMS in the APAMA_HOME\samples\correlator_jms\simple-send-receive directory.

To make correlator-integrated messaging for JMS available to an Apama project

  1. From the File menu, choose New > Apama Project. This launches the New Apama Project wizard.

  2. In the New Apama Project wizard, give the project a name, and click Next. The second page of the wizard appears, listing the available Apama resource bundles.

  3. Apama’s correlator-integrated messaging for JMS makes use of the Apama correlator-integrated adapter for JMS. From the Select required bundle instances list box, select the JMS (Correlator-integrated support for the Java Message Service) bundle.

  4. Click Finish.

The correlator-integrated adapter for JMS is added to the project’s Connectivity and Adapters node. In addition, all the necessary resources to support correlator-integrated messaging for JMS are generated. Note, you can only add a single instance of the correlator-integrated messaging adapter for JMS to an Apama project.

After you add the correlator-integrated adapter for JMS, you need to configure connections to a JMS broker and configure senders and receivers.

Adding and configuring connections

When you first add the correlator-integrated messaging for JMS bundle to an Apama project, the list of connections is initially empty. You can add one or more connection to JMS providers.

To establish a connection to a JMS broker

  1. In the Project Explorer, expand the project’s Connectivity and Adapters node and then expand the JMS (Correlator-integrated support for the Java Message Service) node.

  2. Double-click the adapter’s instance. This opens the instance’s configuration in the editor for the correlator-integrated adapter for JMS.

  3. In the adapter editor’s Settings tab, click the Add Connection button (Plus icon) to display the JMS Configuration Wizard.

  4. In the JMS Configuration Wizard, specify the following:

    1. JMS Provider, select from the drop-down list.

    2. Connection ID must be unique. The connection ID is used throughout the configuration files and Apama application to identify this broker connection. The value for the connection ID should not contain any spaces. The connection ID is used when sending JMS messages from the Apama application. This Apama connection ID is not exposed to the JMS provider in any way.

    3. Description is optional and currently unused.

  5. Click Next.

  6. The Classpath details page of the JMS Configuration Wizard displays the default classpath details for the JMS provider that you selected in the previous step. Add or modify the values as appropriate for your environment.

    To add or modify the classpath details:

    1. The Select Installation Directory field lists the default directory where the JMS provider’s JAR files are located. You can change this directory by clicking the browse button ().

    2. To add an entry to the CLASSPATH, click the Add Classpath button (+) and add the new value in the Add Classpath Variable dialog. You can also remove an entry by selecting it and clicking the Remove Classpath button (x).

  7. Click Next to proceed to the Connection Properties page of the JMS Configuration Wizard. If necessary, add or modify the values as appropriate.

    1. The Use JNDI checkbox indicates the usage of JNDI by JMS providers. For JMS providers that use JNDI, the checkbox is selected. For providers that do not support JNDI, the checkbox is not selected. It is not possible to change the value of the Use JNDI checkbox. If necessary, you can edit the generated XML file after completing the wizard to change how the connection factory is instantiated. For more information about customizing the XML, see XML configuration bean reference and Spring Beans documentation.

    2. By default, the JMS Configuration Wizard lists a subset of standard connection properties. If Use JNDI is enabled, the connection details field shows JNDI Environment properties. If Use JNDI is not enabled, the connection details field shows ConnectionFactory properties. To show the complete list of properties, select the Show advanced properties check box.

    3. You can add and remove properties and you can modify the properties’ values. To modify a value, click in the Value column and enter the required information.

  8. Click Finish.

The adapter editor is updated to display the new connection in the JMS Connections section.

Note: If you are using JNDI to get the connection factory, it is usually necessary to first add and configure a JNDI name for the connection factory you wish to use using the administration tools provided by the JMS implementation you are using. For example, if using Universal Messaging, this would be the Enterprise Manager tool. A common mistake when configuring the JNDI connection factory binding is to use localhost rather than a fully qualified host name or IP address. For many JMS implementations, this will not permit connections from hosts other than the one that the server is running on.

After you establish a connection to a JMS broker, you need to add JMS receivers and specify mapping configurations for receivers and senders.

Adding JMS receivers

JMS receivers are added to JMS connections.

To add a JMS receiver to a project

  1. In the Project Explorer, double-click the project’s correlator-integrated adapter for JMS instance. This opens the instance configuration in Apama’s adapter editor.

  2. Select the desired JMS connection.

  3. In the Static receivers section, click the Add destination button (Plus icon).

    This adds a receiver with a default name to the Name column and a default type (queue) to the Type column.

  4. If desired, you can edit the value in the Name column. You can edit the value in the Type column by clicking the value and selecting a new type from the drop-down list at the right.

After you have configured the JMS receivers for each queue or topic of interest, you need to configure how the received JMS messages will be mapped to Apama events.

Configuring receiver event mappings

Each event mapping for a received JMS message is configured by specifying the target Apama event type, a conditional expression to determine which source JMS messages should be mapped to this event type, and a set of mapping rules that populate the fields of the target Apama event based on the contents of the source JMS message.

To configure an event mapping

  1. Ensure that the Apama event types you wish to use for mapping have been defined in an EPL file in your project.

  2. In the Project Explorer, double-click the project’s correlator-integrated adapter for JMS instance. This opens the instance configuration in Apama’s adapter editor.

  3. In the adapter editor, select the Event Mappings tab.

  4. On the adapter editor’s Event Mappings tab in the Mapping Configuration section, select the Receiver Mapping Configuration tab.

  5. Click the Add Event button (Plus icon) to display the Event Type Selection dialog.

  6. In the Event Type Selection dialog’s Event Type Selection field, enter the name of the event. As you type, event types that match what you enter are shown in the Matching items list.

  7. In the Matching items list, select the name of the event type you want to associate with the JMS message. The name of the EPL file that defines the selected event is displayed in the status area at the bottom of the dialog.

  8. Click OK.

    This updates the display in the adapter editor’s Event Mappings tab to show a hierarchical view of the JMS message on the left (the mapping source) and a hierarchical view of the Apama event on the right (the mapping target). In addition, the Expression column displays a default JUEL conditional expression that determines which JMS messages will use the specified mapping rules. If you need to use a different conditional expression, you can edit the default. For more information see Using conditional expressions.

  9. Map the JMS message to the Apama event by clicking on the entity in the Message tree and dragging a line to the entity in the Event tree. For example, the simplest mapping for a standard JMS TextMessage would be a single mapping rule from JMS Body in the JMS message to a single string field in the Apama event. More complex mapping involves mapping the value of one or more JMS headers or properties or parsing XML content out of the text message. For more information see Mapping Apama events and JMS messages.

If a receiver mapping configuration lists multiple events, the mapper evaluates the expressions from top to bottom, stopping on the first mapping whose conditional expression evaluates to true. You can use the up and down arrows to change the order in which the evaluations are performed.

Using conditional expressions

When you configure event mappings for received JMS messages, you specify Apama event types to which JMS messages will be mapped along with the mapping rules. The correlator-integrated mapper for JMS uses JUEL expressions to indicate which mapping rules to use. JUEL (Java Unified Expression Language) expressions are a standard way to access data. When you specify an event type for a receiver, Apama Plugin for Eclipse creates a default conditional expression that evaluates a JMS property named MESSAGE_TYPE, testing to see if its value is the name of the specified Apama event type. You can modify the default expression if you need to test for a different condition, depending on the format of the JMS messages that Apama will be receiving.

Depending on your application’s needs, you can create a conditional expression for the following cases:

  • Match a JMS header
  • Match a JMS property
  • If the XML document root element exists
  • Match an XPath into the JMS message body

To specify a custom conditional expression

  1. On the Receiver Mapping Configuration tab, click the expression in the Expression column.

  2. Click the Browse button next to the expression. This displays the Conditional Expression dialog, where you can edit the default expression.

  3. In the Condition field, select the type of conditional expression you want from the drop-down list. Depending on your selection, the remaining available fields will vary.

  4. Fill in the remaining fields as required. For some fields you select from drop-down lists, for others you enter values directly. If you select the Custom type of conditional expression, you can edit the expression directly. If a string literal in the expression contains a single or double quotation mark, it needs to be escaped with the backslash character ( \' or \" ).

  5. Click OK. The new expression is displayed in the Expression column of the Receiver Mapping Configuration tab.

Conditional operators in custom expressions. The following operators are available:

  • == equal to
  • != not equal
  • lt less than
  • gt greater than
  • le less than or equal
  • ge greater than or equal
  • and
  • or
  • empty null or empty
  • not

A number of methods are available for common string operations such as the ones listed below.

  • contains()
  • endsWith()
  • equals()
  • equalsIgnoreCase()
  • matches()
  • startsWith()

For a complete list of the available methods as well as details for using these methods, see JUEL mapping expressions reference for JMS.

Custom conditional expression examples. In most cases the decision about which Apama event type to map to for a given JMS message is based on a JMS message property value or sometimes a header, such as JMSType. In other cases, when there is no alternative, the decision is made by parsing XML content in the document body and evaluating an XPath expression over it. Here are some examples of typical conditional expressions.

  • JUEL boolean expression based on a JMS string property value:

    ${jms.property['MY_MESSAGE_TYPE'] == 'MyMessage1'}
    
  • JUEL boolean expression based on a JMS header value:

    ${jms.header['JMSType'] == 'MyMessage1'}
    
  • JUEL boolean expression based on the existence of the XML root element message1 in the body of a TextMessage:

    ${xpath(jms.body.textmessage, 'boolean(/message1)')}
    
  • JUEL boolean expression based on testing the value of an XML attribute in the body of a TextMessage:

    ${xpath(jms.body.textmessage, '/message/info/@messageType') == 'MyMessage'}
    
  • JUEL boolean expression for matching based on message type (TypeMessage, MapMessage, BytesMessage, ObjectMessage, or Message):

    ${jms.body.type == 'TextMessage'}
    

The following boolean JUEL expressions show advanced cases demonstrating what is possible using JUEL and illustrating how the syntax works with example XML documents.

  • JUEL expression that matches all messages:

    ${true}
    
  • “greater than” numeric operator:

    ${jms.property['MY_LONG_PROPERTY'] gt 120}
    
  • Using backslash to escape quotes inside a JUEL expression:

    ${jms.body.textmessage == 'Contains \'quoted\' string'}
    
  • Operators not, and, or, and empty:

    ${not (jms.property['MY_MESSAGE_TYPE'] == 'MyMessage1' or
                        jms.property['MY_MESSAGE_TYPE'] == 'MyMessage2') and
                        not empty jms.property['MY_MESSAGE_TYPE']}
    
  • Testing the value of an entry in the body of a MapMessage:

    ${jms.body.mapmessage['myMessageTypeKey'] == 'MapMessage1'}
    
  • An advanced XPath query (and use of JUEL double-quoted string literal and XPath single-quoted string literal in the same expression)

    ${xpath(jms.body.textmessage, " (count(/message3/e) > 2) and
             /message3/e[2] = 'there' and
             (/message3/e[1] = /message3/e[3]) ")}
    

    For an XML document such as

    <message3><e>Hello</e><e>there</e><e>Hello</e></message3>
    
  • XPath namespace support:

    ${xpath(jms.body.textmessage, " /message4/*[local-name()='element1' and
             namespace-uri()='http://www.myco.com/testns']/text() ") ==
             'Hello world'}
    

    For an XML document such as

    <message4 xmlns:myprefix="http://www.myco.com/testns">
           <element1>No namespace</element1>
           <myprefix:element1>Hello world</myprefix:element1></message4>
    
  • Recursively parsing XML content nested in the CDATA section of another XML document:

    ${xpath( xpath(jms.body.textmessage, '/messageA/text()'),
             '/messageB/text()') == 'MyNestedMessageType'}
    

    For an XML document such as

    <messageA><![CDATA[
       <messageB>MyNestedMessageType</messageB> ]]>
    </messageA>
    
  • Check if a JMS string property value contains the specified value:

    ${jms.property['MY_MESSAGE_TYPE'].contains('Apama')}
    
  • Check if a JMS TextMessage body matches the specified regular expression:

    ${jms.body.textmessage.matches('.*inb*[ou]*r') }
    

For a table of expressions for getting and setting values in JMS messages and recommended mappings to Apama event types, see JUEL mapping expressions reference for JMS.

Adding a classpath variable entry

You can add an entry to the JMS provider’s connection classpath using the New Classpath Variable dialog.

To add a classpath variable entry

  1. In the Project Explorer, double-click the project’s correlator-integrated adapter for JMS instance. This opens the instance configuration in Apama’s adapter editor.

  2. Select the desired JMS connection.

  3. Expand the Classpath section and click the Add Classpath Variable button (Icon).

    This displays the New Classpath Variable dialog.

  4. From the Choose Group drop-down list, select the group that represents the JMS connection.

  5. If desired, add a Variable Name and Variable Value (either both fields must be filled in or both must be blank).

    When you create a variable in this dialog, you can use it as a shorthand way of specifying locations when you want to add several JAR files from the same location. If you specify the name of a previously defined variable in the Variable Name field, the Variable Value field is automatically filled in.

  6. In the Jar Name field, enter the name of the JAR file or click the Browse button and select the JAR file.

  7. Click OK.

Configuring sender event mappings

Each event mapping for a JMS message to be sent is configured by specifying the source Apama event type, and a set of mapping rules that populate the target JMS message from the fields of the source Apama event.

To configure an event mapping

  1. Ensure that the Apama event types you wish to use for mapping have been defined in an EPL file in your project.

  2. If necessary, in the Project Explorer, double-click the project’s correlator-integrated adapter for JMS instance. This opens the instance configuration in Apama’s adapter editor.

  3. Select the JMS connection.

  4. In the correlator-integrated adapter for JMS editor, select the Event Mappings tab.

  5. On the adapter editor’s Event Mappings tab, select the Sender Mapping Configuration tab.

  6. On the Sender Mapping Configuration tab, click the Add Event button (Plus icon) to display the Event Type Selection dialog.

  7. In the Event Type Selection dialog’s Event Type Selection field, enter the name of the event. As you type, event types that match what you enter are shown in the Matching items list.

  8. In the Matching items list, select the name of the event type you want to associate with the JMS message. The name of the EPL file that defines the selected event is displayed in the status area at the bottom of the dialog.

  9. Click OK.

    This updates the display in the adapter editor’s Event Mappings tab to show a hierarchical view of the Apama event on the left (the mapping source) and a hierarchical view of the JMS message on the right (the mapping target).

  10. Create a mapping rule as follows:

    1. If necessary, click on the event to be mapped in the Event Name column.

    2. Click on the entity in the event tree and drag a line to the entity in the message tree.

    For example, a simple mapping would be from a single string field in an Apama event to JMS Body in the JMS message. More complex mappings might involve mapping an event field to a specific JMS property. For more information see Mapping Apama events and JMS messages.

  11. Specify the message’s JMS destination in either of two ways:

    • Specify a constant value in the event type’s mapping:

      Constant value

      For more information on specifying a constant value, see Using expressions in mapping rules

    • Specify a destination in an event field and map that field to the message:

      Destination

    Note destination is always specified as topic:*name*, queue:*name*, or jndi:*name*.

Using EPL to send and receive JMS messages

The EPL code necessary for using correlator-integrated messaging for JMS is minimal.

  • Initialization - Your application needs to notify the correlator that the application has been injected and is ready to process events from the JMS broker.

    1. Apama recommends that after all an application’s EPL has been injected, the application should send an application-defined “start” event using a .evt file. Using an event is clearer and more reliable than enabling JMS message receiving using monitor onload() actions because it is easier to guarantee that all EPL has definitely been injected and is in a good state before the event is sent and JMS message receiving commences.

      Apama Plugin for Eclipse, engine_deploy and other tools all ensure that .evt files are sent in after all EPL has been injected.

    2. The monitor that handles the application-defined start event (from step 1) should use this JMS event object to notify correlator-integrated messaging for JMS that the application is initialized and ready to receive messages, for example:

      on com.mycompany.myapp.Start() {
         com.apama.correlator.jms.JMS.onApplicationInitialized();
         // Any other post-injection startup logic goes here too.
      }
      

    Note:

    For simple applications, you can add the EPL bundle Automatic onApplicationInitialized to your project (see also Adding bundles to projects). This bundle will ensure that onApplicationInitialized is called as soon as the entire application has been injected into the correlator. However, in cases where you need to wait for a MemoryStore, database or another resource to be prepared before your application is able to begin to process incoming messages, you should not use the bundle. In these cases, you should write your own start event and application logic.

  • Receiving events - After configuring a JMS receiver, add EPL listeners for the events specified in the mapping configuration.

  • Sending events - Send the Apama event associated with the JMS message in the Sender Mapping Configuration by using the following syntax:

    send event_name to "jms:*senderId*";
    

    Note that *senderId* is typically “*connectionId*-default-sender” unless explicitly configured with a different name. For example, to send an event to the default sender on a connection called “MyConnection”, use the following:

    send MyEvent to "jms:MyConnection-default-sender";
    

For more information on specifying the message’s JMS destination, see Configuring sender event mappings.