TIF ENOVIA/3DExperience Connector - Reply Handler
A typical use case is when you transfer data to a messaging queue and you expect a reply from the "other" system onto a reply-queue, then you need some functionality that consumes messages from the reply-queue in order to update the job status in TIF; e.g. mark the job as succeeded or failed.
Currently, you may handle replies using a configurable reply handler from following sources:
- File system
-
Support for receiving events from the OS when a file is changed/added in a directory may be used to communicate reply status.
- JMS
-
Consume messages from a particular JMS queue used for replies
- IBM/Native MQ
-
Consume messages from an IBM MQ queue used for replies
- RabbitMQ/AMQP
-
Consume messages from a Rabbit MQ queue
- Kafka
-
Consume messages from a Kafka topic
A reply handler will take care about most of the details regarding receiving the reply and perform the internal calls inside TIF but provide extension points were necessary. For example, allow evaluating if the reply represents a positive or negative response.
A reply handler works like this
-
Get/obtain message from some source
-
From the message and its source - map to the originating Job / Transfer
-
This is typically done either via correlation id or through some custom evaluation
-
-
Based upon the content of the message, evaluate if the response is successful or failing
-
This is the place were you will need to plugin some code that does this evaluation.
-
-
Update the TIF internally
Configuration Location
A reply handler is defined in an XML resource within the ${TIF_ROOT}/modules/enovia/cfg
directory of type "replyhandler".
Example:
$\{TIF_ROOT}/modules/enovia/cfg/replyhandler/MyReplyHandler.xml
$\{TIF_ROOT}/modules/enovia/cfg/domain/replyhandler/MyReplyHandler.xml
these configuration files are referenced as
tvc:replyhandler/MyReplyHandler.xml
tvc:replyhandler:domain/MyReplyHandler.xml
Configuration Format
A configuration defines the following aspects:
-
The source
-
How the mapping between message and Job id is made
-
How to evaluate the status
-
If you need an ENOVIA/3DEXPERIENCE context available during the execution. (default none is allocated)
Let’s look at the configuration format. Note that this is not a valid example it just illustrates all configuration aspects.
<ReplyHandler>
<Source>
<JMS id="eco-reply" /> (1)
<NativeMQ id="mq-eco-reply" />
<RabbitMQ id="rabbitmq-eco-reply" />
<Kafka id="kafka-reply" />
<File id="file-in-1" replyFor="file-out-1"/>
</Source>
<JobIdLocator className="com.acme.custom.MyJobLocator" /> (2)
<JobIdLocator script="MyIDLocator.js" />
<JobIdLocator script="tvc:script/MyIDLocator.js" />
<JobIdLocator script="tvc:script:domain/AnotherIDLocator.js" />
<JobIdLocator>
importClass(com.technia.tif.enovia.job.reply.config.JobIDLocator.ID);
function locate(msg) {
...
return new ID(UUID.fromString(jobId), transferId);
}
</JobIdLocator>
<StatusEvaluator className="com.acme.custom.MyStatusEvaluator" /> (3)
<StatusEvaluator script="MyStatusEvaluator.js" />
<StatusEvaluator script="tvc:script/MyStatusEvaluator.js" />
<StatusEvaluator script="tvc:script:domain/AnotherStatusEvaluator.js" />
<StatusEvaluator>
function evaluate(ctx) {
ctx.setResult(true, "OK");
}
</StatusEvaluator>
<WithContext /> (4)
</ReplyHandler>
1 | Either one of these sources can be used per reply handler |
2 | The JobID locator |
3 | The StatusEvaluator |
4 | Optionally element that, if present, will allocate a context for you. |
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. |
Both the job-id locator and status-evaluator may be implemented in a few different ways:
-
A Java class implementing either
com.technia.tif.enovia.job.reply.config.JobIDLocator
for JobIdLocator andcom.technia.tif.enovia.job.reply.config.StatusEvaluator
for StatusEvaluator. -
A script stored inside its own file using the script resource type.
-
An inline script.
In some cases you may not need a JobID locator. See next chapter(s). |
If you are using Java 8, the internal Java Script engine has been changed so you may need to change your old legacy scripts written prior to Java 8 by adding the following at the top of your script:
|
JMS Source
The supported attributes on the JMS element are shown in the table below
Attribute | Description | Required |
---|---|---|
id |
The id of the corresponding destination |
Yes |
messageSelector |
A message selector that filters messages. See below for details |
No |
transacted |
Boolean defining transaction mode |
No. Default is false |
ackMode |
One of "auto","client" or "dups_ok" |
No. Default is auto |
consumerCount |
Defines number of concurrent consumers. Typically used with destination listening to a queue. |
No. Default is 1 |
shareConnection |
Boolean defining if to share connection per destination with other JMS listeners. The common default value can be configured with property |
No |
For handling of replies from a JMS messaging systems the correlation id is used to correlate the message to its "source" in TIF.
If you have changed the format of the correlation id in the outgoing message, you need to apply changes in the reply handler. |
By default, the message selector that is used for a JMS Source is set to
JMSCorrelationID like '${tif.instance.id}|%'
The macro is resolved at runtime to the id of the TIF instance.
This means that only messages matching this correlation id will be fetched for the TIF instance in question. This is particularly useful in situations where you have multiple TIF instances listening to the same queues. In such case it is important that only the TIF instance that sent the original message will receive the reply.
If you are using the default correlation id on the outgoing JMS message, you do not need to define a JobIdLocator
at all since the mapping can be done automatically.
Example config for JMS source were response message is of type TextMessage and the status is provided as a property on the message object.
<ReplyHandler>
<Source>
<JMS id="eco-reply" />
</Source>
<StatusEvaluator>
function evaluate(ctx) {
var msg = ctx.getMessage().getText();
var succeeded = ctx.getMessge().getBooleanProperty("success");
ctx.setResult(succeeded, msg);
}
</StatusEvaluator>
</ReplyHandler>
Rabbit MQ Source
The supported attributes on the RabbitMQ
element are shown in the table below
Attribute | Description | Required |
---|---|---|
id |
The id of the corresponding destination |
Yes |
Replies from a Rabbit MQ messaging system uses the correlation id of the message to correlate the message to its "source" in TIF.
If you have changed the format of the correlation id in the outgoing message, you need to apply changes in the reply handler. |
By default, outgoing messages from TIF to RabbitMQ uses a correlation id that contains the following information
-
TIF instance id
-
Job id
-
Transfer id
The TIF instance id is needed in order to be able to correlate messages to the correct TIF instance. E.g ensure that the same TIF instance that sent the original message will handle the reply.
If you are using the default correlation id on the outgoing Rabbit MQ message,
you do not need to define a JobIdLocator
at all since the mapping can be done automatically.
Example config.
<ReplyHandler>
<Source>
<RabbitMQ id="eco-reply" />
</Source>
<StatusEvaluator>
function evaluate(ctx) {
var msg = ctx.getMessage().getBodyAsString();
var succeeded = ctx.getProperties().getHeaders().get("status");
ctx.setResult(succeeded, msg);
}
</StatusEvaluator>
</ReplyHandler>
Native MQ Source
The supported attributes on the NativeMQ element are shown in the table below
Attribute | Description | Required |
---|---|---|
id |
The id of the corresponding destination |
Yes |
defaultMatchGroupId |
Whether or not if to match on group id’s. Note that per default this attribute is based upon the TIF setting See also this chapter. By default TIF will match messages based upon their group-id’s. |
No |
messageId |
Used to specify match option on the message-id |
No |
correlationId |
Used to specify match option on the correlation-id |
No |
groupId |
Used to specify match option on the group-id |
No |
seqNumber |
Used to specify match option on the sequence number |
No |
For handling of replies from a JMS messaging systems the correlation id is used to correlate the message to its "source" in TIF.
If you have changed the format of the correlation id in the outgoing message, you need to apply changes in the reply handler. |
Example config for Native MQ source.
<ReplyHandler>
<Source>
<NativeMQ id="MQ.QM1.M3.REPLY" />
</Source>
<StatusEvaluator>
function evaluate(ctx) {
....
ctx.setResult(succeeded, msg);
}
</StatusEvaluator>
</ReplyHandler>
Kafka Source
The supported attributes on the <Kafka>
element are shown in the table below
Attribute | Description | Required |
---|---|---|
id |
The id of the corresponding destination |
Yes |
topic |
Specifies the Kafka topic to consume records from |
Yes unless the mapped destination have a default topic defined. |
clientId |
A client identifier |
No |
groupId |
Specifies the group identifier. This is used to join the Kafka consumer with a specific consumer group |
Yes. |
instanceIdHeader |
Specifies the name of the header on the record we consume that will contain the TIF instance value. This is only needed in case you have multiple TIF instances that may consume records from the same topics. In such case you must consider the source of the record. |
Depends |
jobIdHeader |
Specifies the name of the header on the record that will contain the TIF Job ID |
Yes |
destinationIdHeader |
Specifies the name of the header on the record that will contain the TIF destination id, which the record is a reply for. Note that you can omit this header and instead specify a static value in the |
Depends |
replyFor |
Specifies a fixed destination id value. All records consumer are considered being originated for this destination. Either this attribute or the |
Depends |
Example config for Kafka source.
<ReplyHandler>
<Source>
<Kafka id="kafka-reply-dest"
groupId="test-group"
topic="plm-reply"
jobIdHeader="jobId"
replyFor="kafka-dest" />
</Source>
<StatusEvaluator>
function evaluate(ctx) {
....
ctx.setResult(succeeded, msg);
}
</StatusEvaluator>
</ReplyHandler>
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 |
File Source
Some use cases involves creating files in folders that are watched by other applications. In order to receive status updates from such operation, you can use a File source to listen into a folder, which the other system is responding into.
<ReplyHandler>
<Source>
<File id="file-dest-2"
replyFor="file-dest-1"/>
</Source>
<StatusEvaluator className="com.technia.tif.enovia.job.reply.config.SimpleFileStatusEvaluator" />
</ReplyHandler>
In this example we use the default ID locator, which assumes that the file name is the "job id" + an optional suffix.
In the destinations.xml
file you may define the outgoing file destination like below in order to include the job-id in the outgoing file-name.
<Destinations>
<File id="file-dest-1"
directory="${tif.temp}/transfer/out"
fileName="${job.id}.xml"/>
<File id="file-dest-2"
directory="${tif.temp}/transfer/in"/>
</Destinations>
Moreover, we use a built-in status evaluator that has a very simple implementation:
public void evaluate(ReplyHandlerContext ctx) {
Path p = ctx.getMessage();
String dirName = p.getParent().getFileName().toString();
boolean error = "error".equalsIgnoreCase(dirName);
ctx.setResult(!error, readFileContent(p));
}
Startup of Reply Handler
Upon startup, TIF will automatically find all reply handler configurations that you have configured and deploy these. This method is called auto-registration and can be disabled if wanted. Below is a table of properties that are of interest.
Property | Type | Default | Description |
---|---|---|---|
resources.replyHandler.autoRegister |
boolean |
True |
Use this property to disable the auto registration |
resources.replyHandler.excluded |
Comma separated list |
Comma separated list of resources to be excluded. |
|
resources.replyHandler.included |
Comma separated list |
Comma separated list of resources to be included. |
By default, auto registration is enabled and no resources are excluded.
In earlier versions of TIF, you were forced to specify the reply handler configurations
to be started within the ${TIF_ROOT}/modules/enovia/etc/module.custom.properties
file.
This method is still supported, although the preferred approach is to auto-register
all configurations without having to also do extra configuration within the "module.custom.properties" file.
To deploy a reply handler using the old approach, see instructions below:
replyHandler.<id>.<property> = <value>
Below is an example where two different reply handlers has been configured.
replyHandler.0.config = ECOReply.xml
replyHandler.1.config = tvc:replyhandler:domain/PartReply.xml
Refering to configurations in the default domain do not require the complete expanded name. E.g. |
Each reply handler may be stopped / restarted from the TIF Administration UI. |
The most common configuration requires only the "config" property to be defined. However, there are additional properties available as shown below:
replyHandler.<id>.enabled = true (1)
replyHandler.<id>.config = ... (2)
replyHandler.<id>.className = ... (3)
1 | May be used to disable a particular reply handler |
2 | Specifies the reply handler configuration |
3 | Instead of a configuration, specify a Java class implementing com.technia.tif.enovia.job.reply.ReplyHandler |
The earlier properties like shown below to control the ENOVIA/3DEXPERIENCE context settings, are no longer supported.
You should configure this from within the reply handler instead using the See previous chapter. |
Monitoring Async Replies
To get control of the replies that are expected to come back to TIF from the other system(s), you can enable a scheduled task called "Async Reply Supervisor".
This task will typically run every night and find transfers that lack replies and flag these to allow someone to take some action.
There are some configuration properties within the module.properties
file that controls this scheduled task.
See below for an example:
asyncReplySupervisor.enabled=true
asyncReplySupervisor.execute=0 10 2 * * ?
asyncReplySupervisor.overDueTime=7d
asyncReplySupervisor.overDueReport.recipients=tif-admin-1@acme.com;tif-admin-2@acme.com
asyncReplySupervisor.overDueAction=mark-failed
asyncReplySupervisor.overDueAction.delay=5d
The overdue-time is the time-threshold that we expect a reply to be delivered. If there are jobs having transfers fulfilling the criteria, the scheduled task will send out email to the recipients listed.
After sending the email notification, there will be a period of time, in this case 5 days, which the administrator has some possibility to take action. If the transfer after these 5 days still has not received any reply, the associated job will be marked as failed.