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.
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 (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:
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.
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:
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. |
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. |
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. |
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:
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:
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. |
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.
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.
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 '_'.
This name translator is used to translate JMS names to AMQP names. It replaces any underscore character '_' with a dash '-'.
This name translator does not change anything. It just returns what is passed as input name.
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 Router.
package com.swiftmq.impl.amqp.amqp.v01_00_00.transformer;
public interface NameTranslator
{
public String translate(String source);
}
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".