Message Transformer

Notes

All configuration examples in this sections are done with SwiftMQ Explorer. After finishing the configuration, the changes need to be saved to the routerconfig.xml. This can be done by selecting the router node, right click, "Save this Configuration":

After save have a look at <swiftmqinstall>/config/router1/routerconfig.xml to see the XML configuration which is document HERE.

Introduction

Message transformer are located under entity "Declarations":

They are declared per default and/or per destination (queue or topic). AMQP specifies a message format id which is actually a version number. Current message format is 0. Message transformers are declared per message format id so that messages of different message format ids can be handled by different message transformer.

Default Transformer

Default transformer (inbound or outbound) are used if there is no destination transformer declared.

If there is no default inbound transformer declared, the AMQP Swiftlet creates an default inbound transformer for message format 0 and class com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.JMSMappingInboundTransformer. The same takes place if no default outbound transformer is declared but with class com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.JMSMappingOutboundTransformer.

The following steps show how to create a default inbound transformer (use similar steps to create a default outbound transformer).

1) Select entity "Default Inbound Transformer", right click, "Create a new Entity":

2) Enter the message format id for which the transformer should be used and the class name:

3) The transformer is now declared and uses the default values of its properties (see sections below). To change a property, select the "Properties" entity of the transformer, right click, "Create a new Entity":

4) Now enter name and value of the property:

Destination Transformer

Transformer can also be declared per destination (queue/topic). These overwrite the default transformer.

The destination name refers to the address field of the source respective target of the AMQP attach frame. For example, if a consumer is created on queue "testqueue", it looks like the above. However, if a producer is created on "testqueue@router2" (fully qualified name of a remote queue) then the name must be also "testqueue@router2". The destination transformer must be declared at the router where the producer/consumer is connected to.

Inbound Transformer

An inbound transformer transforms an AMQP message to a JMS message. It is an abstract base class for which these properties can be configured:

Property Default Description
name-translator com.swiftmq.impl.amqp.amqp.v01_00_00.transformer. InvalidToUnderscoreNameTranslator Name translator class, see last section.
prefix-vendor JMS_AMQP_ JMS-Vendor property prefix. "JMS_AMQP_" as per AMQP spec.
default-delivery-mode PERSISTENT Delivery mode which is set in the target JMS message.
default-priority Message.DEFAULT_PRIORITY Priority which is set in the target JMS message.
default-ttl Message.DEFAULT_TIME_TO_LIVE Time to live which is set in the target JMS message.

An AMQP message might be split over multiple transfer frames. The payloads of all transfer frames of a message transfer are collected before the inbound transformer is called.

There are 2 predefined specializations of the inbound transformer which both inherit the above properties:

  • com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.AMQPNativeInboundTransformer
  • com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.JMSMappingInboundTransformer

AMQPNativeInboundTransformer

Full class name:

            com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.AMQPNativeInboundTransformer

This transformer stores the whole AMQP message as the body of a JMS BytesMessage. The body will be opaque while the message travels through SwiftMQ. This means that a message selector on message fields (header, properties) can NOT be applied to these kind of messages because they have not been extracted.

Resulting JMS BytesMessage:

Header/Property Type Description
JMSMessageID String Unique message id.
JMSTimestamp long Set to System.currentTimeMillis().
JMSExpiration long If default-ttl > 0: set to System.currentTimeMillis()+<default-ttl>.
JMSDeliveryMode int DeliveryMode.PERSISTENT or DeliveryMode.NON_PERSISTENT.
JMSPriority int <default-priority>.
<prefix-vendor>MESSAGE_FORMAT long Message format id of the AMQP message.
<prefix-vendor>NATIVE boolean Set to true to flag as native AMQP. This can be used by JMS clients to filter these messages out because they can only be processed by AMQP clients.

JMSMappingInboundTransformer

Full class name:

            com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.JMSMappingInboundTransformer

The following properties can be configured in addition to the properties of the base class InboundTransformer:

Property Default Description
message-factory com.swiftmq.impl.amqp.amqp.v01_00_00.transformer. BodyTypeMessageFactory Message factory to create JMS messages. There is only this one currently.
prefix-delivery-annotations DA_ Prefix for property names from delivery annotations.
prefix-message-annotations MA_ Prefix for property names from message annotations.
prefix-footer FT_ Prefix for property names from the footer.
overwrite-message-id false False: message id from the AMQP message is used. True: a new message id is generated.
jms-type-property null A name of a property inside the application properties of a message that will be transformed to the JMSType of the resulting JMS message. It overwrite the default "x-opt-jms-type" entry in message annotations. See below.

This transformer decodes the body of the AMQP message and uses the BodyTypeMessageFactory to create a JMS message which type depends on the body of the AMQP message:

AMQP Message Body Type Resulting JMS Message Type
Data BytesMessage
AmqpSequence StreamMessage
AmqpValue with a symbol or string TextMessage
AmqpValue with a binary BytesMessage
AmqpValue with a list StreamMessage
AmqpValue with a map MapMessage
AmqpValue with everything else ObjectMessage with an java.io.Serializable according to the following conversion table
AMQP Primitive java.io.Serializable
bool Boolean
byte Byte
ubyte Integer
short Integer
ushort Integer
int Integer
uint Long
long Long
ulong Long
double Double
float Float
char Integer
string String
symbol String
timestamp long
binary byte[]

Non-body sections of the AMQP message are transformed according to this conversion table:

AMQP Message JMS Message
header:durable JMSDeliveryMode
header:priority JMSPriority
header:ttl JMSExpiration
header:first-aquirer <prefix-vendor>FirstAcquirer
header:delivery-count JMSXDeliveryCount
delivery-annotations:<name> <prefix-vendor><prefix-delivery-annotations><name>
message-annotations:x-opt-jms-type JMSType
message-annotations:<name> <prefix-vendor><prefix-message-annotations><name>
properties:message-id JMSMessageID (may be overwritten by a generated message id)
properties:user-id JMSXUserID
properties:to JMSDestination
properties:subject <prefix-vendor>Subject
properties:reply-to JMSReplyTo
properties:correlation-id JMSCorrelationID
properties:content-type <prefix-vendor>ContentType
properties:content-encoding <prefix-vendor>ContentEncoding
properties:absolute-expiry-time JMSExpiration
properties:creation-time JMSTimeStamp
properties:group-id JMSXGroupID
properties:group-sequence JMSXGroupSeq
properties:reply-to-group-id <prefix-vendor>ReplyToGroupID
application-properties:<name> <name>
footer:<name> <prefix-vendor><prefix-footer><name>

Names (<name>) will be translated by the configured name translator of the base class. See last section.

Stream- and MapMessage support only certain types of values. The resulting message is flagged with an error property if another type is detected. The same takes place if the value of the AMQP type is not a java.io.Serializable. The name of the error property is <propertyname>_ERROR. For example, if application-property "OrderID" has an invalid value, the corresponding error property would "OrderID_ERROR".

Like the native transformer, the JMS Mapping transformer sets these additional properties:

Header/Property Type Description
<prefix-vendor>MESSAGE_FORMAT long Message format id of the AMQP message.
<prefix-vendor>NATIVE boolean Set to false to flag as non-native AMQP.

Outbound Transformer

An outbound transformer transforms a JMS message to an AMQP message. It is an abstract base class for which these properties can be configured:

Property Default Description
name-translator com.swiftmq.impl.amqp.amqp.v01_00_00.transformer. NullNameTranslator Name translator class, see last section.
prefix-vendor JMS_AMQP_ JMS-Vendor property prefix. "JMS_AMQP_" as per AMQP spec.

There are 2 predefined specializations of the outbound transformer which both inherit the above properties:

  • com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.AMQPNativeOutboundTransformer
  • com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.JMSMappingOutboundTransformer

AMQPNativeOutboundTransformer

Full class name:

            com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.AMQPNativeOutboundTransformer

This transformer is the counterpart of the AMQPNativeInboundTransformer and creates an AMQP message directly from the body byte[] of a JMS BytesMessage. The following conditions must be fulfilled:

  • Input JMS Message MUST be a BytesMessage.
  • Message property <prefix-vendor>NATIVE (boolean) MUST exist and MUST be set to true.
  • Message property <prefix-vendor>MESSAGE_FORMAT (long) MUST exist.

JMSMappingOutboundTransformer

Full class name:

            com.swiftmq.impl.amqp.amqp.v01_00_00.transformer.JMSMappingOutboundTransformer

The following properties can be configured in addition to the properties of the base class OutboundTransformer:

Property Default Description
body-factory com.swiftmq.impl.amqp.amqp.v01_00_00.transformer. MessageTypeBodyFactory Body factory to create AMQP messages. There is only this one currently.
prefix-delivery-annotations DA_ Prefix for property names from delivery annotations.
prefix-message-annotations MA_ Prefix for property names from message annotations.
prefix-footer FT_ Prefix for property names from the footer.
jms-type-property null A name of a property inside the application properties of a message where the JMSType of the source JMS message is transformed to. It overwrite the default "x-opt-jms-type" entry in message annotations. See below.

This transformer transforms a JMS message into an AMQP message and uses the MessageTypeBodyFactory to create the body of the AMQP message according to the following conversion table:

JMS Message Type Resulting AMQP Message Body
BytesMessage Data
TextMessage AmqpValue with a string
MapMessage AmqpValue with a map, values converted according following conversion table.
StreamMessage AmqpSequence, values converted according following conversion table.
ObjectMessage AmqpValue with an AMQP primitive according to the following conversion table
java.io.Serializable AMQP Primitive
Boolean bool
Byte byte
Char char
Short short
Integer int
Long long
Double double
Float float
String string
byte[] binary

Header and properties of the JMS message are transformed to the respective sections of the AMQP message according to this conversion table:

JMS Message AMQP Message
JMSDeliveryMode header:durable
JMSPriority header:priority
JMSExpiration header:ttl
<prefix-vendor>FirstAcquirer header:first-aquirer
JMSXDeliveryCount header:delivery-count
<prefix-vendor><prefix-delivery-annotations><name> delivery-annotations:<name>
JMSType message-annotations:x-opt-jms-type
<prefix-vendor><prefix-message-annotations><name> message-annotations:<name>
JMSMessageID properties:message-id
JMSXUserID properties:user-id
JMSDestination properties:to
<prefix-vendor>Subject properties:subject
JMSReplyTo properties:reply-to
JMSCorrelationID properties:correlation-id
<prefix-vendor>ContentType properties:content-type
<prefix-vendor>ContentEncoding properties:content-encoding
JMSExpiration properties:absolute-expiry-time
JMSTimeStamp properties:creation-time
JMSXGroupID properties:group-id
JMSXGroupSeq properties:group-sequence
<prefix-vendor>ReplyToGroupID properties:reply-to-group-id
<name> application-properties:<name>
<prefix-vendor><prefix-footer><name> footer:<name>

Names (<name>) will be translated by the configured name translator of the base class. See last section.

Name Translator

In order to work in SQL-based message selectors, property names in JMS are limited to that of Java identifiers. AMQP does not have these restrictions so a translation must takes place. The AMQP Swiftlet predefines 3 name translators which should fit most requirements. If not, custom implementations can be created.

InvalidToUnderscoreNameTranslator

This name translator is used to translate AMQP names to JMS names. It replaces any character which must not be start or part of a Java identifier with an underscore '_'.

UnderscoreToDashNameTranslator

This name translator is used to translate JMS names to AMQP names. It replaces any underscore character '_' with a dash '-'.

NullNameTranslator

This name translator does not change anything. It just returns what is passed as input name.

Custom Implementations

To create a custom name translator, implement the following interface. It is defined in sys$amqp.jar located under <swiftmqinstall>/kernel/sys$amqp. Put the class of the custom implementation in a jar file and store it under <swiftmqinstall>/kernel/sys$amqp. The class is available after restart of the SwiftMQ Universal Router.

    package com.swiftmq.impl.amqp.amqp.v01_00_00.transformer;

    public interface NameTranslator
    {
      public String translate(String source);
    }

Filter Translation

SwiftMQ supports the following filters which will be announced in the "offerered capabilities" of the Open frame:

        APACHE.ORG:NO_LOCAL
        APACHE.ORG:SELECTOR

If the connecting client announces "APACHE.ORG:SELECTOR" in the "offerered capabilities" or "desired capabilities" of its Open frame, the field names of the selector filter are translated from normalized AMQP names used by Apache Qpid into JMS field names, e.g. "amqp.priority = 4" will be translated to "JMSPriority = 4".