TIF ENOVIA/3DExperience Connector - Kafka Message Listener

You may want to listen for records (messages) from an Apache Kafka topic. This page describes how to set-up a so called kafka message listener in TIF.

Configuration Details

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

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.kafkalistener.autoRegister

boolean

True

Use this property to disable the auto registration

resources.kafkalistener.excluded

Comma separated list

Comma separated list of resources to be excluded.

resources.kafkalistener.included

Comma separated list

Comma separated list of resources to be included.

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

XML Configuration Format

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

Element Required Description Example

<Name>

Yes

Defines a user friendly name of this configuration

<Name>Some Name</Name>

<Topic>

Yes

Defines one or more topics to subscribe to.

Use separate tags in case you subscribe to multiple topics.

<Topic>MyTopic</Topic>

<GroupId>

Yes

Defines the consumer group this consumer belongs to

<GroupId>TEST</GroupId>

<ClientId>

No

Defines a custom client identifier

<ClientId>TIF_${tif.instance.id}</ClientId>

<OnError>

No

Defines what should happen in case of an error occurs while processing a record.

Per default, TIF will stop processing further records if this happens. Otherwise the record would be committed and it would be difficult to recover from such state.

You can however specify that TIF should continue work with future records by setting this to "continue".

<OnError>continue</OnError>

<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="…​" />

<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.kafka.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:KafkaListener
    xmlns:tif="http://technia.com/TIF/KafkaListener"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://technia.com/TIF/KafkaListener file:///C:/apps/tif-server/modules/enovia/schema/KafkaListener.xsd">
    <tif:Name>Test Listener</tif:Name>
    <tif:Topic>TIF-JOB-TEST</tif:Topic>
    <tif:GroupId>TEST_GROUP</tif:GroupId>
    <tif:OnError>continue</tif:OnError>
    <tif:Destination id="kafka-dest-001" />
    <tif:WithContext />
    <tif:Handler className="com.acme.integrations.DefaultMessageReceiver" />
</tif:KafkaListener>

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 KAfka 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.

This is configured within the "module.properties" file within the etc folder. See page this page for details how to modify this file.

Below is an example configuration:

kafkalistener.test.enabled = false
kafkalistener.test.destination = kafka-1
kafkalistener.test.topic = TIF-JOB-TEST
kafkalistener.test.groupId = TEST_GROUP
#kafkalistener.test.className = com.technia.tif.enovia.kafka.service.DefaultMessageReceiver
kafkalistener.test.type = CreateUpdateIntegration
kafkalistener.test.configuration = Part_from_ERP.xml

The prefix of a kafka listener is kafkaListener.<NAME>. where <NAME> is a unique name containing only letters and/or digits.

The available property suffices are shown in the table below.

Property Suffix Description Required

enabled

Defines if the kafka listener should be enabled or not.

No. Default is true

destination

The ID of a kafka 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.

className

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

topic

Defines the topic to subscribe to. For multiple topic subscription, separate with a comma.

Yes

groupId

Defines the consumer group to which this listener is a member of

Yes

clientId

Defines an arbitrary client identifier

No

onError

Defines behavior for the listener if an exception occurs. Per default, onError is set to stop but can be changed to continue if desired

No

Java Class

The Java class pointed out via the className attribute and must implement the interface com.technia.tif.enovia.kafka.MessageReceiver.

Example skeleton below:

import org.apache.kafka.clients.consumer.ConsumerRecord;

import com.technia.tif.enovia.kafka.MessageReceiver;
import com.technia.tif.enovia.kafka.MessageContext;
import com.technia.tif.enovia.kafka.Result;

public class MyConsumer implements MessageReceiver {

    @Override
    public Result onMessage(MessageContext ctx) {
        ConsumerRecord record = ctx.getRecord();
        // ...
        return result;
    }
}

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 a resource file.

Examples:

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

The script you write must implement at least the "onMessage" method.

Example:

function onMessage(ctx) {
    var record = ctx.getRecord();
    // do something
    return ...;
}