TIF ENOVIA/3DExperience Connector - JMS Message Receiver

A JMS listener can be setup in order to receive messages from a JMS queue or topic. This page describes how to set up a so called JMS Message Receiver in TIF.

Configuration Details

You can set up several JMS listeners, each will then listen to different queues or topics.

The preferred way of configuring such listener is to use the XML configuration format. E.g. adding a file within the directory ${TIF_ROOT}/modules/enovia/cfg/jmslistener.

By default, this directory is scanned upon startup and all configured listeners therein will be registered automatically. You can configure this behavior within ${TIF_ROOT}/modules/enovia/etc/module.custom.properties via the following properties:

Property Type Default Description

resources.jmsListener.autoRegister

boolean

True

Use this property to disable the auto registration

resources.jmsListener.excluded

Comma separated list

Comma separated list of resources to be excluded.

resources.jmsListener.included

Comma separated list

Comma separated list of resources to be included.

Auto registration is enabled by default and no resources are excluded.

XML Configuration Format

The root element is <JMSListener>. The table below lists the allowed child elements

Element Required Description Example

<Name>

Yes

Defines a user-friendly name of this configuration

<Name>Part Queueue</Name>

<Destination>

Yes

Defines what destination to listen from

<Destination id="dest-xy"/>

<WithContext>

No

Defines if to establish an ENOVIA/3DEXPERIENCE context

<WithContext user="Integration User"/>

<Handler>

Yes

Defines the handler containing your business logic that is processing the message

<Handler className="…​" /> <Handler type="…​" /> <Handler script="…​" />

<MessageSelector>

No

Can be used to specify a selector, which then will limit the messages based upon the criteria in the selector.

<MessageSelector>criteria</MessageSelector>

<ConsumerCount>

No

Defines number of concurrent consumers. Typically used with destination listening to a queue.

Too high consumer count will result in performance degradation.

<ConsumerCount>2</ConsumerCount>

<ShareConnection>

No

Boolean defining if to share connection per destination with other JMS listeners.

The common default value can be configured with property jms.listener.shareConnection in ${TIF_ROOT}/modules/enovia/etc/module.custom.properties

<ShareConnection>true</ShareConnection>

<Arguments>

No

Some handlers might accept arguments, these can be set like shown in the example

<Arguments>
<Argument name="name-of-arg">value</Argument>
<Argument name="another-arg" value="different format" />
</Arguments>

<ReplyTo>

No

This element allows specifying to where the reply message will be sent.

In most cases the destination to where the reply should be sent is part of the message itself. However, in some cases this information is either not present or you need to override the destination. In those cases you should add the <ReplyTo> element to control this.

This element requires the destinationId attribute to be set.

There is an additional attribute called override, which default is set to true. This attribute controls if we should override any destination set on the incoming message. Setting this to false means reply to the destination specifyed on the incoming message if present, otherwise reply to the destination defined by the <ReplyTo> element.

<ReplyTo destinationId="jms-dest-part-updated" />

<Transacted>

No

If you write your own Handler, then the transacted flag is defined by the Handler. You can however override the transacted flag via this element.

This element is typically used together with a pre-defined handler specified via the type, where you dont have control of the implementation details of the handler.

<Transacted>true</Transacted>

<AckMode>

No

If you write your own Handler, then the ack mode is defined by the Handler. You can however override the ack mode via this element.

Possible values are:

  • auto (default)

  • client

  • dups_ok

This element is typically used together with a pre-defined handler specified via the type attribute, where you don’t have control over the implementation details of the handler.

<AckMode>client</AckMode>

<Durable>

No

The durability can either be set on the destination itself or defined/overridden on the listener.

If set to true, TIF will create a durable subscriber to a topic. Note that this requires both that the destination itself is configured for a topic and not a queue AND that you are using a JMS client compatible with JMS 2.0 (for the javax namespace).

You can also control the name of the subscription by either setting the name attribute or specify with the <SubscriptionName> element. If not set, the ID of the destination is used as subscription name.

A durable subscriber also requires that you have a unique client id set. This is done in the Destinations file using the clientId attribute.

<Durable>true</Durable>

<SubscriptionName>

No

If durable is configured, this element can be used to control the name of the subscription.

<SubscriptionName>sub1</SubscriptionName>

or alternatively

<Durable name='sub1'>true</Durable>

The <WithContext> element supports the following attributes.

Attribute Required Description

user

No

If omitted, the super user will be used

securityContext

No

Defines the security context to be used

useDefaultSecurityContext

No

If set to true, the default security context for the user will be used.

The used user must have a default security context otherwise an error will be raised.

The <Handler> element supports one of these three attributes

className

The name of a class implementing com.technia.tif.enovia.jms.MessageReceiver. See chapter below.

script

Name of a script resource. Example: script="tvc:script/MyMessageReceiver.js". See chapter below.

type

Name of a pre-defined type. Example: type="SomePredefinedType"

Examples of pre-defined handlers are:

CreateUpdateIntegration

Can be used to trigger the create/update integration using the message body as input for the process.
Required arguments: configuration
Optional arguments: objectIdParam, payloadconfig

PrintMessage

Prints the content of the message to std-out. This can be used for debugging purposes.

MoveMessage

Can be used to move a message from one destination to another. The incoming message is moved to the destination as configured in the reply section.
Optional arguments: delay

TransformXML

Can be used to transform data using XSLT and push transformed data onto another queue.
Arguments: stylesheet, json-in, json-out

Example configuration:

<tif:JMSListener
    xmlns:tif="http://technia.com/TIF/JMSListener"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://technia.com/TIF/JMSListener file:///C:/apps/tif-server/modules/enovia/schema/JMSListener.xsd">
    <tif:Name>Test Listener</tif:Name>
    <tif:Destination id="part-from-erp" />
    <tif:WithContext />
    <tif:Handler className="com.acme.integrations.part.DefaultMessageReceiver" />
</tif:JMSListener>

another example:

<JMSListener>
	<Name>Move from queue: jms.Test</Name>
	<Destination id="jms-test" />
	<MessageSelector>JMSCorrelationID like '${tif.instance.id}|%'</MessageSelector>
	<Handler type="MoveMessage" />
	<Arguments>
		<Argument name="delay">5000</Argument>
	</Arguments>
	<ConsumerCount>1</ConsumerCount>
	<ShareConnection>true</ShareConnection>
	<Transacted>true</Transacted>
	<ReplyTo destinationId="foo">
		<Header name="..." value="..." />
	</ReplyTo>
</JMSListener>

When TIF is running in development mode, you can edit, create or delete configurations at runtime and those will be hot deployed automatically without the need to restart the TIF instance or take any further action.

However, in production mode, you can only edit a definition at runtime, but in order to take the changes into use you need to restart the corresponding service activator from within the Administration UI. Add or delete configurations is not supported.

See also this chapter for more info

Registration via Module Properties

The recommended way of registering a JMS listener is to use the XML configuration format as described in the previous chapter. However, you may still register a listener from with the module properties file. E.g. using the file ${TIF_ROOT}/modules/enovia/etc/module.custom.properties.

Below is an example configuration:

jmsListener.0.enabled = true
jmsListener.0.className = com.technia.tif.enovia.jms.TestReceiver
jmsListener.0.destination = jms-1
jmsListener.0.context = true
jmsListener.0.name = Service Name

The prefix of a JMS listener is jmsListener.<ID>. where <ID> is a unique identifier containing only letters and/or digits.

The available property suffices are shown in the table below.

Property Suffix Description Required

enabled

Defines if the directory listener should be enabled or not.

No. Default is true

destination

The ID of a JMS destination defined in the "destination.xml" file. See Configure Destinations for details how to register destinations.

Yes

context

A boolean value indicating if an ENOVIA/3DEXPERIENCE context object should be allocated when the message receiver is invoked.

No. Default is false.

context.user

An optional name of a ENOVIA/3DEXPERIENCE user (used if context = true). May be omitted to indicate that the default ENOVIA/3DEXPERIENCE system-user should be used.

No. Defaults to the system user.

context.securityContext

Specify ENOVIA/3DEXPERIENCE security context.

No

context.useDefaultSecurityContext

Specify to use the default security context on the user.

No

name

Name of the service. Used in the Admin UI.

No.

messageSelector

Optional string used for selecting messages. See this page for additional information.

No.

className

Defines a fully qualified class name of a Java class either:

  • Implements "com.technia.tif.enovia.jms.MessageReceiver"

  • Extends from "com.technia.tif.enovia.jms.MessageReceiverAdapter".

See below.

One of the attributes className or script must be defined.

script

A script that implements the same functionality as a corresponding Java class. See below.

Java Class

The Java class pointed out via the className attribute must implement the interface MessageReceiver in TIF. This API looks like:

package com.technia.tif.enovia.jms;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import com.technia.tif.core.annotation.API;

/**
 *
 * @author Technia
 * @since 2 maj 2013
 */
@API
public interface MessageReceiver {

    /**
     * Called prior to the JMS connection and session is closed. Note that there
     * is no guarantee that this method is invoked, however, you can implement
     * this method if you need to release any resource you have opened.
     */
    void close();

    /**
     * @return True if to use transactions.
     */
    boolean isTransacted();

    /**
     * @return The acknowledgemode. Must be any of the integer constants defined
     *         in the Session class.
     */
    int getAcknowledgeMode();

    /**
     * Called when a new message appears.
     *
     * @param message The message to handle
     * @throws Exception
     */
    void onMessage(Message message) throws Exception;

    /**
     * If an exception occurs, this method is called.
     *
     * @param exception The JMS exception
     */
    void onException(JMSException exception);

    /**
     * Called upon creation of a response message.
     *
     * @param session
     * @param message
     * @return
     * @throws JMSException
     * @since 2015.3.0
     */
    Message createResponseMessage(Session session, Message message) throws JMSException;
}

For convenience, there is an adapter class available called com.technia.tif.enovia.jms.MessageReceiverAdapter that can be used instead. This adapter class only has one abstract method, namely "onMessage". This adapter class returns false for the "isTransacted" and "Session.AUTO_ACKNOWLEDGE" for the acknowledge mode as default.

For incoming messages that have a replyTo destination set, TIF will call the createResponseMessage method, which allows you to create the proper message to be re-delivered back to the sender.

Script

Instead of implementing the MessageReceiver as a traditional Java class you may implement this in a script file.

Scripts are stored and handled as an XML resource file, described in here.

Examples:

jmsListener.TEST.script = JMSListener.js (1)
jmsListener.TEST.script = tvc:script/JMSListener.js (2)
jmsListener.TEST.script = tvc:script:domain/JMSListener.js (3)
1 refers to the file cfg/script/JMSListener.js
2 refers to the file cfg/script/JMSListener.js
3 refers to the file cfg/domain/script/JMSListener.js

The script you write must as a minimum implement the "onMessage" method, and you may implement the others defined in the interface. The default value for isTransacted is FALSE and Session.AUTO_ACKNOWLEDGE for the acknowledge mode.

Example:

function onMessage(msg) {
    // do something
}

function isTransacted() {
    return false;
}

Durable Subscription

Example how to setup a durable topic subscription.

${TIF_ROOT}/etc/destinations.xml
<JMS id="my-topic"
     initialContextFactory="org.apache.activemq.jndi.ActiveMQInitialContextFactory"
     durable="true"
     user="name-of-user"
     password="secret"
     clientId="tif-1-test-1"
     providerURL="the-url">
     <Topic name="test.&gt;" jndiKey="topic.%s" />
</JMS>
${TIF_ROOT}/modules/enovia/cfg/jmslistener/MyListener.xml
<JMSListener>
    <Name>My Test Listener</Name>
    <Destination id="my-topic" />
    <Handler type="PrintMessage" />
    <Arguments>
        <Argument name="format">json</Argument>
    </Arguments>
</JMSListener>

Note that you need to use a JMS 2.0 compatible client, which is using the Javax namepsace and not Jakarta.