blob: 278b73c2dd677efa470cf3ac9d624b5232db459e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using Apache.NMS.Util;
using Apache.NMS.XMS.Util;
using IBM.XMS;
namespace Apache.NMS.XMS
{
/// <summary>
/// Represents a message either to be sent to a message broker or received
/// from a message broker.
/// </summary>
class Message : Apache.NMS.IMessage
{
public IBM.XMS.IMessage xmsMessage;
#region Constructors
/// <summary>
/// Constructs a <c>Message</c> object.
/// </summary>
/// <param name="message">XMS message.</param>
public Message(IBM.XMS.IMessage message)
{
this.xmsMessage = message;
}
#endregion
#region IMessage Members
#region Acknowledgement
/// <summary>
/// If using client acknowledgement mode on the session then this
/// method will acknowledge that the message has been processed
/// correctly.
/// </summary>
public void Acknowledge()
{
try
{
this.xmsMessage.Acknowledge();
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
#endregion
#region Message body
private bool readOnlyMsgBody = false;
/// <summary>
/// Whether the message body is read-only.
/// </summary>
public virtual bool ReadOnlyBody
{
get { return this.readOnlyMsgBody; }
set { this.readOnlyMsgBody = value; }
}
/// <summary>
/// Clears out the message body. Clearing a message's body does not
/// clear its header values or property entries.
/// If this message body was read-only, calling this method leaves
/// the message body in the same state as an empty body in a newly
/// created message.
/// </summary>
public void ClearBody()
{
try
{
this.ReadOnlyBody = false;
this.xmsMessage.ClearBody();
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
#endregion
#region Message properties
#region General comments
// https://docs.oracle.com/cd/E19798-01/821-1841/bnces/index.html
// A JMS message has three parts: a header, properties, and a body.
// A JMS message header contains a number of predefined fields that
// contain values that both clients and providers use to identify
// and to route messages:
// Header Field Set By
// JMSDestination send or publish method
// JMSDeliveryMode send or publish method
// JMSExpiration send or publish method
// JMSPriority send or publish method
// JMSMessageID send or publish method
// JMSTimestamp send or publish method
// JMSCorrelationID Client
// JMSReplyTo Client
// JMSType Client
// JMSRedelivered JMS provider
// Properties can be created and set for messages if values are needed
// in addition to those provided by the header fields.
// The JMS API provides some predefined property names that a provider
// can support. The use either of these predefined properties or of
// user-defined properties is optional.
// The JMS API defines five message body formats:
// Message Type Body Contains
// TextMessage A java.lang.String object.
// MapMessage A set of name-value pairs, with names as String
// objects and values as primitive types.
// BytesMessage A stream of uninterpreted bytes.
// StreamMessage A stream of primitive values, filled and read
// sequentially.
// ObjectMessage A Serializable object.
// Message Nothing. Composed of header fields and properties
// only.
//
// http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.msc.doc/xms_cmesmod.htm?lang=en
// The XMS message model is the same as the WebSphere® MQ classes for
// JMS message model.
// In particular, XMS implements the same message header fields and
// message properties that WebSphere MQ classes for JMS implements:
// JMS header fields. These fields have names that commence
// with the prefix JMS.
// JMS defined properties. These fields have properties whose names
// commence with the prefix JMSX.
// IBM® defined properties. These fields have properties whose names
// commence with the prefix JMS_IBM_.
//
// Apache.NMS redefines JMS message header fields with an "NMS" prefix:
// JMS NMS IBM.XMS
// Destination JMSDestination IDestination NMSDestination IDestination JMSDestination
// int JMSDeliveryMode MsgDeliveryMode NMSDeliveryMode DeliveryMode JMSDeliveryMode
// long JMSExpiration [TimeSpan NMSTimeToLive] Int64 JMSExpiration
// int JMSPriority MsgPriority NMSPriority Int32 JMSPriority
// String JMSMessageID string NMSMessageId String JMSMessageID
// long JMSTimestamp DateTime NMSTimestamp Int64 JMSTimestamp
// String JMSCorrelationID string NMSCorrelationID String JMSCorrelationID
// Destination JMSReplyTo IDestination NMSReplyTo IDestination JMSReplyTo
// String JMSType string NMSType String JMSType
// boolean JMSRedelivered bool NMSRedelivered Boolean JMSRedelivered
// Properties are set and retrieved through typed SetXxxProperty and
// GetXxxProperty methods.
// Unlike JMS, Apache.NMS does not expose those methods in the
// IMessage interface, but through the IPrimitiveMap interface,
// implemented by the MessageProperties class, exposed through
// the IMessage.Properties property.
// The MessagePropertyIntercepter propertyHelper intercepts get and
// set invocations on properties whose name starts with "NMS", and
// maps them to the equivalent message header fields through
// reflection. Other invocations are routed to the
// MessageProperties.Get/SetObjetProperty methods, which in turn
// invokes xmsMessage.Get/SetObjectProperty.
//
// XMS message properties are:
// XMSC.JMS_DESTINATION = "JMSDestination"
// XMSC.JMS_DELIVERY_MODE = "JMSDeliveryMode"
// XMSC.JMS_EXPIRATION = "JMSExpiration"
// XMSC.JMS_PRIORITY = "JMSPriority"
// XMSC.JMS_MESSAGEID = "JMSMessageID"
// XMSC.JMS_TIMESTAMP = "JMSTimestamp"
// XMSC.JMS_CORRELATIONID = "JMSCorrelationID"
// XMSC.JMS_REPLYTO = "JMSReplyto"
// XMSC.JMS_TYPE = "JMSType"
// XMSC.JMS_REDELIVERED = "JMSRedelivered"
//
// XMSC.JMSX_USERID = "JMSXUserID"
// XMSC.JMSX_APPID = "JMSXAppID"
// XMSC.JMSX_DELIVERY_COUNT = "JMSXDeliveryCount"
// XMSC.JMSX_GROUPID = "JMSXGroupID"
// XMSC.JMSX_GROUPSEQ = "JMSXGroupSeq"
// XMSC.JMSX_STATE = "JMSXState"
// XMSC.JMSX_PRODUCER_TXID = "JMSXProducerTXID"
// XMSC.JMSX_CONSUMER_TXID = "JMSXConsumerTXID"
// XMSC.JMSX_RCV_TIMESTAMP = "JMSXRcvTimestamp"
// XMSC.JMS_IBM_REPORT_EXCEPTION = "JMS_IBM_Report_Exception"
// XMSC.JMS_IBM_REPORT_EXPIRATION = "JMS_IBM_Report_Expiration"
// XMSC.JMS_IBM_REPORT_COA = "JMS_IBM_Report_COA"
// XMSC.JMS_IBM_REPORT_COD = "JMS_IBM_Report_COD"
// XMSC.JMS_IBM_REPORT_NAN = "JMS_IBM_Report_NAN"
// XMSC.JMS_IBM_REPORT_PAN = "JMS_IBM_Report_PAN"
// XMSC.JMS_IBM_REPORT_PASS_MSG_ID = "JMS_IBM_Report_Pass_Msg_ID"
// XMSC.JMS_IBM_REPORT_PASS_CORREL_ID = "JMS_IBM_Report_Pass_Correl_ID"
// XMSC.JMS_IBM_REPORT_DISCARD_MSG = "JMS_IBM_Report_Discard_Msg"
// XMSC.JMS_IBM_MSGTYPE = "JMS_IBM_MsgType"
// XMSC.JMS_IBM_FEEDBACK = "JMS_IBM_Feedback"
// XMSC.JMS_IBM_FORMAT = "JMS_IBM_Format"
// XMSC.JMS_IBM_PUTAPPLTYPE = "JMS_IBM_PutApplType"
// XMSC.JMS_IBM_ENCODING = "JMS_IBM_Encoding"
// XMSC.JMS_IBM_CHARACTER_SET = "JMS_IBM_Character_Set"
// XMSC.JMS_IBM_PUTDATE = "JMS_IBM_PutDate"
// XMSC.JMS_IBM_PUTTIME = "JMS_IBM_PutTime"
// XMSC.JMS_IBM_LAST_MSG_IN_GROUP = "JMS_IBM_Last_Msg_In_Group"
// XMSC.JMS_IBM_EXCEPTIONREASON = "JMS_IBM_ExceptionReason"
// XMSC.JMS_IBM_EXCEPTIONTIMESTAMP = "JMS_IBM_ExceptionTimestamp"
// XMSC.JMS_IBM_EXCEPTIONMESSAGE = "JMS_IBM_ExceptionMessage"
// XMSC.JMS_IBM_SYSTEM_MESSAGEID = "JMS_IBM_System_MessageID"
// XMSC.JMS_IBM_EXCEPTIONPROBLEMDESTINATION = "JMS_IBM_ExceptionProblemDestination"
// XMSC.JMS_IBM_ARM_CORRELATOR = "JMS_IBM_ArmCorrelator"
// XMSC.JMS_IBM_WAS_RM_CORRELATOR = "JMS_IBM_RMCorrelator"
// XMSC.JMS_IBM_CONNECTIONID = "JMS_IBM_ConnectionID"
// XMSC.JMS_IBM_RETAIN = "JMS_IBM_Retain"
// XMSC.JMS_IBM_MQMD_REPORT = "JMS_IBM_MQMD_Report"
// XMSC.JMS_IBM_MQMD_MSGTYPE = "JMS_IBM_MQMD_MsgType"
// XMSC.JMS_IBM_MQMD_EXPIRY = "JMS_IBM_MQMD_Expiry"
// XMSC.JMS_IBM_MQMD_FEEDBACK = "JMS_IBM_MQMD_Feedback"
// XMSC.JMS_IBM_MQMD_ENCODING = "JMS_IBM_MQMD_Encoding"
// XMSC.JMS_IBM_MQMD_CODEDCHARSETID = "JMS_IBM_MQMD_CodedCharSetId"
// XMSC.JMS_IBM_MQMD_FORMAT = "JMS_IBM_MQMD_Format"
// XMSC.JMS_IBM_MQMD_PRIORITY = "JMS_IBM_MQMD_Priority"
// XMSC.JMS_IBM_MQMD_PERSISTENCE = "JMS_IBM_MQMD_Persistence"
// XMSC.JMS_IBM_MQMD_MSGID = "JMS_IBM_MQMD_MsgId"
// XMSC.JMS_IBM_MQMD_CORRELID = "JMS_IBM_MQMD_CorrelId"
// XMSC.JMS_IBM_MQMD_BACKOUTCOUNT = "JMS_IBM_MQMD_BackoutCount"
// XMSC.JMS_IBM_MQMD_REPLYTOQ = "JMS_IBM_MQMD_ReplyToQ"
// XMSC.JMS_IBM_MQMD_REPLYTOQMGR = "JMS_IBM_MQMD_ReplyToQMgr"
// XMSC.JMS_IBM_MQMD_USERIDENTIFIER = "JMS_IBM_MQMD_UserIdentifier"
// XMSC.JMS_IBM_MQMD_ACCOUNTINGTOKEN = "JMS_IBM_MQMD_AccountingToken"
// XMSC.JMS_IBM_MQMD_APPLIDENTITYDATA = "JMS_IBM_MQMD_ApplIdentityData"
// XMSC.JMS_IBM_MQMD_PUTAPPLTYPE = "JMS_IBM_MQMD_PutApplType"
// XMSC.JMS_IBM_MQMD_PUTAPPLNAME = "JMS_IBM_MQMD_PutApplName"
// XMSC.JMS_IBM_MQMD_PUTDATE = "JMS_IBM_MQMD_PutDate"
// XMSC.JMS_IBM_MQMD_PUTTIME = "JMS_IBM_MQMD_PutTime"
// XMSC.JMS_IBM_MQMD_APPLORIGINDATA = "JMS_IBM_MQMD_ApplOriginData"
// XMSC.JMS_IBM_MQMD_GROUPID = "JMS_IBM_MQMD_GroupId"
// XMSC.JMS_IBM_MQMD_MSGSEQNUMBER = "JMS_IBM_MQMD_MsgSeqNumber"
// XMSC.JMS_IBM_MQMD_OFFSET = "JMS_IBM_MQMD_Offset"
// XMSC.JMS_IBM_MQMD_MSGFLAGS = "JMS_IBM_MQMD_MsgFlags"
// XMSC.JMS_IBM_MQMD_ORIGINALLENGTH = "JMS_IBM_MQMD_OriginalLength"
// XMSC.JMS_TOG_ARM_CORRELATOR = "JMS_TOG_ARM_Correlator"
#endregion
#region General methods
private bool readOnlyMsgProperties = false;
/// <summary>
/// Whether the message properties is read-only.
/// </summary>
public virtual bool ReadOnlyProperties
{
get { return this.readOnlyMsgProperties; }
set
{
if(this.propertyHelper != null)
{
this.propertyHelper.ReadOnly = value;
}
this.readOnlyMsgProperties = value;
}
}
/// <summary>
/// Clears a message's properties.
/// The message's header fields and body are not cleared.
/// </summary>
public void ClearProperties()
{
try
{
this.ReadOnlyProperties = false;
this.xmsMessage.ClearProperties();
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
private Apache.NMS.IPrimitiveMap properties = null;
private Apache.NMS.Util.MessagePropertyIntercepter propertyHelper;
/// <summary>
/// Provides access to the message properties (headers)
/// </summary>
public Apache.NMS.IPrimitiveMap Properties
{
get
{
if(properties == null)
{
properties = XMSConvert.ToMessageProperties(this.xmsMessage);
propertyHelper = new Apache.NMS.Util.MessagePropertyIntercepter(
this, properties, this.ReadOnlyProperties);
}
return propertyHelper;
}
}
#endregion
#region Message header fields
/// <summary>
/// The correlation ID used to correlate messages from conversations
/// or long running business processes.
/// </summary>
public string NMSCorrelationID
{
get
{
try
{
return this.xmsMessage.JMSCorrelationID;
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
return null;
}
}
set
{
try
{
this.xmsMessage.JMSCorrelationID = value;
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
}
/// <summary>
/// The destination of the message.
/// </summary>
public Apache.NMS.IDestination NMSDestination
{
get
{
return XMSConvert.ToNMSDestination(
this.xmsMessage.JMSDestination);
}
set
{
try
{
this.xmsMessage.JMSDestination =
XMSConvert.ToXMSDestination(value);
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
}
protected TimeSpan timeToLive;
/// <summary>
/// The amount of time that this message is valid for.
/// <c>null</c> if this message does not expire.
/// </summary>
public TimeSpan NMSTimeToLive
{
get { return this.timeToLive; }
set { this.timeToLive = value; }
}
/// <summary>
/// The message ID which is set by the provider.
/// </summary>
public string NMSMessageId
{
get { return this.xmsMessage.JMSMessageID; }
set { this.xmsMessage.JMSMessageID = value; }
}
/// <summary>
/// Whether or not this message is persistent.
/// </summary>
public MsgDeliveryMode NMSDeliveryMode
{
get
{
return XMSConvert.ToNMSMsgDeliveryMode(
this.xmsMessage.JMSDeliveryMode);
}
set
{
try
{
this.xmsMessage.JMSDeliveryMode =
XMSConvert.ToJMSDeliveryMode(value);
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
}
/// <summary>
/// The Priority on this message.
/// </summary>
public MsgPriority NMSPriority
{
get
{
return (MsgPriority)this.xmsMessage.JMSPriority;
}
set
{
try
{
this.xmsMessage.JMSPriority = (int)value;
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
}
/// <summary>
/// Returns true if this message has been redelivered to this or
/// another consumer before being acknowledged successfully.
/// </summary>
public bool NMSRedelivered
{
get { return this.xmsMessage.JMSRedelivered; }
set
{
throw new NMSException("JMSRedelivered cannot be set.");
}
}
/// <summary>
/// The destination that the consumer of this message should send
/// replies to.
/// </summary>
public Apache.NMS.IDestination NMSReplyTo
{
get
{
return XMSConvert.ToNMSDestination(
this.xmsMessage.JMSReplyTo);
}
set
{
try
{
this.xmsMessage.JMSReplyTo =
XMSConvert.ToXMSDestination(value);
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
}
/// <summary>
/// The timestamp of when the message was pubished in UTC time. If the
/// publisher disables setting the timestamp on the message, the time
/// will be set to the start of the UNIX epoch (1970-01-01 00:00:00).
/// </summary>
public DateTime NMSTimestamp
{
get { return DateUtils.ToDateTime(this.xmsMessage.JMSTimestamp); }
set { this.xmsMessage.JMSTimestamp = DateUtils.ToJavaTime(value); }
}
/// <summary>
/// The type name of this message.
/// </summary>
public string NMSType
{
get { return this.xmsMessage.JMSType; }
set
{
try
{
this.xmsMessage.JMSType = value;
}
catch(Exception ex)
{
ExceptionUtil.WrapAndThrowNMSException(ex);
}
}
}
#endregion
#endregion
#endregion
#region Event handlers
public virtual void OnSend()
{
this.ReadOnlyProperties = true;
this.ReadOnlyBody = true;
}
public virtual void OnMessageRollback()
{
}
#endregion
}
}