To provide flexible, high-performing message transfer between mapped destinations, a JMS bridge offers these features:
A JMS bridge uses the connection factories configured for link sources, link targets, and DMQs to create connections to the Message Queue broker and the external JMS provider. When making connections, the JMS bridge follows these rules to determine whether to use a pooled connection, a shared connection, or a dedicated connection:
For link source connections, the JMS bridge always uses a dedicated connection.
For link target and DMQ connections, the JMS bridge uses:
A pooled connection if the link target's or DMQ's stay-connected attribute is false and the connection factory has no JMS client identifier configured.
A dedicated connection if the link target's or DMQ's stay-connected attribute is true or if the link target's or DMQ's clientid attribute is set
A shared connection in all other cases
Each JMS bridge includes a built-in XA transaction coordinator that enables its links to be configured as "transacted" such that message transfer from the source to the target is done in a XA distributed transaction.
For a link to be configured as transacted, both the link source and link target must specify connection factories of type javax.jms.XAConnectionFactory.
The built-in XA transaction coordinator logs transaction records using the same type of store as the Message Queue broker in which the JMS bridge resides. For file-based transaction logging, the transaction log for a JMS bridge is located at:
IMQ_VARHOME/instances/brokerInstance/bridges/bridgeName/txlog.bridgeNane |
For JDBC-based transaction logging, the built-in XA transaction coordinator uses the same JDBC store as the Message Queue broker in which the JMS bridge resides.
When a JMS bridge is started, it registers all its Resource Managers (RMs) with the built-in XA transaction coordinator so that the coordinator can identify specific RMs during recovery.
For connection factories, the JMS bridge only registers the factory as an RM if the factory's multi-rm attribute value is false. A connection factory with a multi-rm attribute value of true should have each of its RMs identified by a connection factory whose multi-rmattribute value of false in order to participate in transactional message transfer. Additionally, the JMS bridge uses a connection factory's ref-name attribute value as part of its RM name when registering RMs with the built-in XA transaction coordinator, so this attribute should not be changed between restarts of the bridge if transaction recovery is desired between restarts.
Message Queue supports JMS bridges in HA broker clusters, but some special constraints apply due to the inherent nature of HA broker clusters:
Each JMS bridge must have a name that is unique across all the JMS bridges in all the brokers in the cluster.
Each JMS bridge must have the same bridge configuration across all the brokers in the cluster.
The imq.bridge.enabled broker property must have the same value across all brokers in the cluster.
Before broker startup, the imq.bridge.activelist broker property for each broker lists only those JMS bridges that are to be owned by that broker.
To ensure that bridges in the cluster have the same configuration across all brokers in the cluster, all bridge-related broker properties except for imq.bridge.activelist should be specified in the centralized cluster properties file defined by the imq.cluster.url broker property.
A table in the cluster's HA store is used to maintain a consistent record of JMS bridge ownership by the brokers in the cluster.
During broker startup, the JMS bridge service compares the broker's imq.bridge.activelist property value to this table's entries before starting any JMS bridges, with the following consequences:
If a JMS bridge named in imq.bridge.activelist does not appear in the table, it is added to the table and associated with the broker.
If a JMS bridge name in imq.bridge.activelist does appear in the table, and the table entry already associates the bridge with a different broker, the bridge name is removed from imq.bridge.activelist.
If an entry in the table associates a JMS bridge with the broker, and that bridge's name is not in imq.bridge.activelist, the bridge name is added to imq.bridge.activelist.
A link target or a DMQ can specify a message transformer to process the message before it is delivered to the target destination or DMQ destination. This message transformer must be a Java class that extends the Message Queue bridge com.sun.messaging.bridge.service.MessageTransformer abstract class and has javax.jms.Message as its formal type parameters. To specify a message transformer, set the message-transformer-class attribute of a link target or a DMQ to the fully qualified class name of the Java class.
During message transfer processing, the JMS message to be transferred to a target, plus any property subelements of the link's target element or the dmq element, are passed to the message transformer's MessageTransformer.transform() method, and the returned JMS message is sent to the target destination.
In a JMS message, the JMSReplyTo header value is provider dependent. Therefore, unless both the source provider and target provider are Message Queue, the JMS bridge sets an existing JMSReplyTo header to a null value before passing the message to a link target or, if specified, the message transformer for the link target.
This default behavior can be overridden by setting the retain-replyto attribute of the link's target element to true. Overriding the default behavior is useful when:
The message transformer for a link target handles processing of the JMSReplyTo header.
Both the link source and link target have the same JMS provider, and clients of the target provider instance need to send reply messages back across the JMS bridge to the JMSReplyTo destination in the source provider instance. To successfully implement this case:
The JMSReplyTo destination must exist (or be able to be auto-created) in the target provider instance.
A JMS bridge link must be defined with its source set to the JMSReplyTo destination in the target provider instance and its target set to the JMSReplyTo destination in the source provider instance.
Each JMS bridge includes a built-in Dead Message Queue (DMQ) named built-in-dmq. This DMQ is a designated Queue destination named imq.bridge.jms.dmq in the broker hosting the JMS bridge. You can also configure additional DMQs for the JMS bridge, in which case the DMQ can use any JMS destination in any configured JMS provider.
In a production environment, the built-in DMQ, imq.bridge.jms.dmq, should be administratively created and have its access controls set appropriately before starting a broker that uses JMS bridge services.
When a DMQ uses Message Queue as the JMS provider, it can be configured such that messages sent to it will automatically be transferred to the Message Queue broker's DMQ. To do so, set physical destination properties of the JMS bridge's DMQ as follows:
useDMQ=true limitBehavior=REMOVE_OLDEST maxNumMsgs=0 |
When a message is sent to the DMQ, the JMS bridge follows this sequence with the built-in DMQ first:
The bridge creates a new DMQ javax.jms.ObjectMessage object and sets the properties listed in Table 12–1 to the ObjectMessage.
If the DMQ has defined a message transformer, the original message is passed to the transformer's MessageTransformer.transform() method.
The body of the javax.jms.ObjectMessage is set to the transformed message (or original message if no message transformer is defined). If this action fails (usually because the message is not serializable), the body of the ObjectMessage is instead set to the toString() value of the original message.
The javax.jms.ObjectMessage is sent (up to send-attempts times) to the DMQ's destination with a timeToLive value based on the DMQ's time-to-live-in-millis attribute and with the same JMSDeliveryMode and JMSPriority as the original message.
If sending the message fails, the bridge repeats Steps 2 through 4 for each DMQ defined in the bridge's XML configuration file in the order they appear in the file, stopping when a send attempt succeeds, unless it is the built-in DMQ.
If the message can't be sent to any DMQ, a log message is generated, containing the properties and headers of the original message and the properties set in Step 1.
Property |
Type |
Description |
---|---|---|
JMS_SUN_JMSBRIDGE_DMQ_BODY_TRUNCATED |
String |
If unable to set the original message or the transformed message (if the DMQ has a message transformer) to the body of the DMQ ObjectMessage. In that case the message's toString() is set to the body of the DMQ ObjectMessage. |
JMS_SUN_JMSBRIDGE_DMQ_EXCEPTION |
String |
The Exception.getMessage() if exception occurred or detailed comments on the failure; null if none. |
JMS_SUN_JMSBRIDGE_DMQ_REASON |
String |
One of: MESSAGE_EXPIRED, SEND_FAILURE, ACK_FAILURE, TRANSFORM_FAILURE, COMMIT_FAILURE. |
JMS_SUN_JMSBRIDGE_DMQ_TIMESTAMP |
String |
The timestamp when the JMS bridge sends the message to the DMQ. |
JMS_SUN_JMSBRIDGE_SOURCE_CORRELATIONID |
String |
The original message's getJMSCorrelationID(). |
JMS_SUN_JMSBRIDGE_SOURCE_DESTINATION |
String |
The original message's source destination name. |
JMS_SUN_JMSBRIDGE_SOURCE_JMSTYPE |
String |
The original message's getJMSType(). |
JMS_SUN_JMSBRIDGE_SOURCE_MESSAGEID |
String |
The orginal message's getJMSMessageID(), or null if not available. |
JMS_SUN_JMSBRIDGE_SOURCE_PROVIDER |
String |
The ConnectionMetaData.getJMSProviderName of the connection the original message was received on; if not available, the source connection factory's getClass().getName(). |
JMS_SUN_JMSBRIDGE_SOURCE_TIMESTAMP |
Long |
The original message's getJMSTimestamp(). |
JMS_SUN_JMSBRIDGE_TARGET_DESTINATION |
String |
The name of the target destination where the original message was intended to send to. |
JMS_SUN_JMSBRIDGE_TARGET_PROVIDER |
String |
The ConnectionMetaData.getJMSProviderName of the connection the original message was intended to send on; if not available, the target connection factory's getClass().getName(). |