23 June 2016

1. RabbitMQ Listener / Message Receiver

You may want to receive messages from a Rabbit MQ message broker. This page describes how to set-up a so called RabbitMQ Message Receiver in TIF allowing you to do so.

1.1. Configuration Details

You can set-up several RabbitMQ 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/rabbitmqlistener.

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

Property Type Default Description

resources.rabbitmqlistener.autoRegister

boolean

True

Use this property to disable the auto registration

resources.rabbitmqlistener.excluded

Comma separated list

Comma separated list of resources to be excluded.

resources.rabbitmqlistener.included

Comma separated list

Comma separated list of resources to be included.

By default, auto registration is enabled and no resources are excluded.

1.1.1. XML Configuration Format

The root element is <AMQPListener>. 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 context

<WithContext user="Integration User"/>

<Handler>

Yes

Defines the handler containing your businesslogic that is processing the message

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

<Arguments>

No

Some handlers might accept arguments.

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

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.rabbitmq.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"

Example configuration:

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

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

1.1.2. Registration via Module Properties

The recommended way of registering a Rabbit-MQ 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:

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

The prefix of a RabbitMQ listener is rabbitmqListener.<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 RabbitMQ 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 context object should be allocated when the message receiver is invoked.

No. Default is false.

context.user

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

No. Defaults to the system user.

context.securityContext

Specify ENOVIA securtity context.

No

context.useDefaultSecurityContext

Specify to use the default securtity context on the user.

No

name

Name of the service. Used in the Admin UI.

No.

className

Defines a fully qualified class name of a Java class that implements "com.technia.tif.enovia.rabbitmq.MessageReceiver". 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.

1.2. 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.rabbitmq;

/**
 * This interface must be implemented to handle messages received by RabbitMQ
 * listener.
 *
 * @since 2015.3.0 Initial version
 * @since 2020.2.0 Refactored to support better message control
 */
public interface MessageReceiver {

    /**
     * Called when a new message appears.
     *
     * @param msg The message to handle
     * @return The result of the operation. Depending on the result, the message
     *         will either be acknowledged (with multiple flag set or not),
     *         not-acknowledged (rejected) (with multiple flag set or not) or
     *         nothing is done.
     * @throws Exception If a failure occurs.
     */
    Result onMessage(Message msg) throws Exception;

    /**
     * If an exception occurs, this method is called. The default implementation
     * does nothing and returns a {@link Result#NACK} value.
     *
     * @param e The exception
     * @param msg The message
     */
    default Result onException(Exception e, Message msg) {
        return Result.NACK;
    }

}

The return value enum constants are described below.

DO_NOTHING

Do nothing

ACK

Acknowledges the current message

NACK

Rejects the current message

NACK_REQUEUE

Rejects the current message and requeues it

ACK_MULTIPLE

Acknowledges multiple messages, e.g. all messages that have not yet been ack/nack’ed

NACK_MULTIPLE

Rejects multiple messages.

NACK_MULTIPLE_REQUEUE

Rejects multiple messages and requeues all.

1.3. Script

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

Scripts are stored and handled similar to any other configuration resource file, e.g. below the cfg folder. The scripts goes into the folder script, e.g. ${TIF_HOME}/modules/enovia/cfg/script. You may also use domains, as for the other configuration files. See below:

Examples:

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

The script you write must implement "onMessage" and "onException" methods.

Example:

function onMessage(msg) {
    // Logic goes here.
    return com.technia.tif.enovia.rabbitmq.Result.ACK;
}

//Override if needed to handle exception
//function onException(e,  msg) {
//
//    return com.technia.tif.enovia.rabbitmq.Result.NACK;
//}