add XML code comments

Minor cleanup
This commit is contained in:
markpollack
2008-11-04 07:18:56 +00:00
parent 52796692fa
commit da43b5c672
25 changed files with 812 additions and 85 deletions

View File

@@ -47,6 +47,12 @@ namespace Spring.Messaging.Core
#region IMessageQueueFactory Members
/// <summary>
/// Registers the message queue, its creation specified via the factory method
/// MessageQueueCreatorDelegate, with the provided name in the application context
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <param name="messageQueueCreatorDelegate">The message queue creator delegate.</param>
public void RegisterMessageQueue(string messageQueueObjectName,
MessageQueueCreatorDelegate messageQueueCreatorDelegate)
{
@@ -55,6 +61,13 @@ namespace Spring.Messaging.Core
applicationContext.ObjectFactory.RegisterSingleton(messageQueueObjectName, mqfo);
}
/// <summary>
/// Creates the message queue given its name in the application context.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <returns>
/// A MessageQueue instance configured via the application context
/// </returns>
public MessageQueue CreateMessageQueue(string messageQueueObjectName)
{
AssertUtils.ArgumentHasText(messageQueueObjectName, "DefaultMessageQueueObjectName");
@@ -72,11 +85,23 @@ namespace Spring.Messaging.Core
return queues[messageQueueObjectName] as MessageQueue;
}
/// <summary>
/// Determines whether the application context contains the message queue object definition.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <returns>
/// <c>true</c> if the application context contains the specified message queue object name; otherwise, <c>false</c>.
/// </returns>
public bool ContainsMessageQueue(string messageQueueObjectName)
{
return applicationContext.ContainsObject(messageQueueObjectName);
}
/// <summary>
/// Registers the message converter.
/// </summary>
/// <param name="messageConverterName">Name of the message converter.</param>
/// <param name="messageConverterCreatorDelegate">The message converter creator delegate.</param>
public void RegisterMessageConverter(string messageConverterName,
MessageConverterCreatorDelegate messageConverterCreatorDelegate)
{
@@ -85,6 +110,13 @@ namespace Spring.Messaging.Core
applicationContext.ObjectFactory.RegisterSingleton(messageConverterName, mcfo);
}
/// <summary>
/// Creates the message converter given its name in the application context.
/// </summary>
/// <param name="messageConverterObjectName">Name of the message converter object.</param>
/// <returns>
/// A IMessageConverter instance configured via the application context
/// </returns>
public IMessageConverter CreateMessageConverter(string messageConverterObjectName)
{
AssertUtils.ArgumentHasText(messageConverterObjectName, "MessgaeFormatterObjectName");
@@ -103,6 +135,13 @@ namespace Spring.Messaging.Core
}
/// <summary>
/// Determines whether the application context contains the message queue object definition.
/// </summary>
/// <param name="messageConverterObjectName">Name of the message converter object.</param>
/// <returns>
/// <c>true</c> if the application context contains the specified message message converter object name; otherwise, <c>false</c>.
/// </returns>
public bool ContainsMessageConverter(string messageConverterObjectName)
{
return applicationContext.ContainsObject(messageConverterObjectName);

View File

@@ -37,21 +37,57 @@ namespace Spring.Messaging.Core
/// <author>Mark Pollack</author>
public interface IMessageQueueFactory
{
/// <summary>
/// Registers the message queue, its creation specified via the factory method
/// MessageQueueCreatorDelegate, with the provided name in the application context
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <param name="messageQueueCreatorDelegate">The message queue creator delegate.</param>
void RegisterMessageQueue(string messageQueueObjectName,
MessageQueueCreatorDelegate messageQueueCreatorDelegate);
/// <summary>
/// Creates the message queue given its name in the application context.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <returns>A MessageQueue instance configured via the application context</returns>
MessageQueue CreateMessageQueue(string messageQueueObjectName);
/// <summary>
/// Determines whether the application context contains the message queue object definition.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <returns>
/// <c>true</c> if the application context contains the specified message queue object name; otherwise, <c>false</c>.
/// </returns>
bool ContainsMessageQueue(string messageQueueObjectName);
/// <summary>
/// Registers the message converter, its creation specified via the factory method
/// MessageConverterCreatorDelegate, with the provided name in the application context.
/// </summary>
/// <param name="messageConverterName">Name of the message converter.</param>
/// <param name="MessageConverterCreatorDelegate">The message converter creator delegate.</param>
void RegisterMessageConverter(string messageConverterName,
MessageConverterCreatorDelegate MessageConverterCreatorDelegate);
/// <summary>
/// Creates the message converter given its name in the application context.
/// </summary>
/// <param name="messageConverterObjectName">Name of the message converter object.</param>
/// <returns>A IMessageConverter instance configured via the application context</returns>
IMessageConverter CreateMessageConverter(string messageConverterObjectName);
/// <summary>
/// Determines whether the application context contains the message queue object definition.
/// </summary>
/// <param name="messageConverterObjectName">Name of the message converter object.</param>
/// <returns>
/// <c>true</c> if the application context contains the specified message message converter object name; otherwise, <c>false</c>.
/// </returns>
bool ContainsMessageConverter(string messageConverterObjectName);

View File

@@ -29,6 +29,10 @@ namespace Spring.Messaging.Core
/// <author>Mark Pollack</author>
public class LocallyExposedMessageQueueResourceHolder : MessageQueueResourceHolder
{
/// <summary>
/// Initializes a new instance of the <see cref="LocallyExposedMessageQueueResourceHolder"/> class.
/// </summary>
/// <param name="messageQueueTransaction">The message queue transaction.</param>
public LocallyExposedMessageQueueResourceHolder(MessageQueueTransaction messageQueueTransaction)
: base(messageQueueTransaction)
{

View File

@@ -269,24 +269,61 @@ namespace Spring.Messaging.Core
#region IMessageQueueOperations Members
/// <summary>
/// Send the given object to the default destination, converting the object
/// to a MSMQ message with a configured IMessageConverter.
/// </summary>
/// <param name="obj">The obj.</param>
/// <remarks>This will only work with a default destination queue specified!</remarks>
public void ConvertAndSend(object obj)
{
CheckDefaultMessageQueue();
ConvertAndSend(DefaultMessageQueueObjectName, obj);
}
/// <summary>
/// Send the given object to the default destination, converting the object
/// to a MSMQ message with a configured IMessageConverter. The IMessagePostProcessor
/// callback allows for modification of the message after conversion.
/// <p>This will only work with a default destination specified!</p>
/// </summary>
/// <param name="obj">the object to convert to a message</param>
/// <param name="messagePostProcessorDelegate">the callback to modify the message</param>
/// <exception cref="MessagingException">if thrown by MSMQ API methods</exception>
public void ConvertAndSend(object obj, MessagePostProcessorDelegate messagePostProcessorDelegate)
{
CheckDefaultMessageQueue();
ConvertAndSend(DefaultMessageQueueObjectName, obj, messagePostProcessorDelegate);
}
/// <summary>
/// Send the given object to the specified destination, converting the object
/// to a MSMQ message with a configured <see cref="IMessageConverter"/> and resolving the
/// destination name to a <see cref="MessageQueue"/> using a <see cref="IMessageQueueFactory"/>
/// </summary>
/// <param name="messageQueueObjectName">the name of the destination queue
/// to send this message to (to be resolved to an actual MessageQueue
/// by a IMessageQueueFactory)</param>
/// <param name="obj">the object to convert to a message</param>
/// <throws>NMSException if there is any problem</throws>
public void ConvertAndSend(string messageQueueObjectName, object obj)
{
Message msg = MessageConverter.ToMessage(obj);
Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), msg);
}
/// <summary>
/// Send the given object to the specified destination, converting the object
/// to a MSMQ message with a configured <see cref="IMessageConverter"/> and resolving the
/// destination name to a <see cref="MessageQueue"/> with an <see cref="IMessageQueueFactory"/>
/// The <see cref="MessagePostProcessorDelegate"/> callback allows for modification of the message after conversion.
/// </summary>
/// <param name="messageQueueObjectName">the name of the destination queue
/// to send this message to (to be resolved to an actual MessageQueue
/// by a IMessageQueueFactory)</param>
/// <param name="obj">the object to convert to a message</param>
/// <param name="messagePostProcessorDelegate">the callback to modify the message</param>
/// <exception cref="MessagingException">if thrown by MSMQ API methods</exception>
public void ConvertAndSend(string messageQueueObjectName, object obj,
MessagePostProcessorDelegate messagePostProcessorDelegate)
{
@@ -295,6 +332,13 @@ namespace Spring.Messaging.Core
Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), msgToSend);
}
/// <summary>
/// Receive and convert a message synchronously from the default message queue.
/// </summary>
/// <returns>The converted object</returns>
/// <exception cref="MessageQueueException">if thrown by MSMQ API methods. Note an
/// exception will be thrown if the timeout of the syncrhonous recieve operation expires.
/// </exception>
public object ReceiveAndConvert()
{
MessageQueue mq = DefaultMessageQueue;
@@ -302,6 +346,14 @@ namespace Spring.Messaging.Core
return DoConvertMessage(m);
}
/// <summary>
/// Receives and convert a message synchronously from the specified message queue.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <returns>the converted object</returns>
/// <exception cref="MessageQueueException">if thrown by MSMQ API methods. Note an
/// exception will be thrown if the timeout of the syncrhonous recieve operation expires.
/// </exception>
public object ReceiveAndConvert(string messageQueueObjectName)
{
MessageQueue mq = MessageQueueFactory.CreateMessageQueue(messageQueueObjectName);
@@ -309,26 +361,64 @@ namespace Spring.Messaging.Core
return DoConvertMessage(m);
}
/// <summary>
/// Receives a message on the default message queue using the transactional settings as dicted by MessageQueue's Transactional property and
/// the current Spring managed ambient transaction.
/// </summary>
/// <returns>A message.</returns>
public Message Receive()
{
return DefaultMessageQueue.Receive(ReceiveTimeout);
}
/// <summary>
/// Receives a message on the specified queue using the transactional settings as dicted by MessageQueue's Transactional property and
/// the current Spring managed ambient transaction.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <returns></returns>
public Message Receive(string messageQueueObjectName)
{
return MessageQueueFactory.CreateMessageQueue(messageQueueObjectName).Receive(ReceiveTimeout);
}
/// <summary>
/// Sends the specified message to the default message queue using the
/// transactional settings as dicted by MessageQueue's Transactional property and
/// the current Spring managed ambient transaction.
/// </summary>
/// <param name="message">The message to send</param>
public void Send(Message message)
{
Send(DefaultMessageQueue, message);
}
/// <summary>
/// Sends the specified message to the message queue using the
/// transactional settings as dicted by MessageQueue's Transactional property and
/// the current Spring managed ambient transaction.
/// </summary>
/// <param name="messageQueueObjectName">Name of the message queue object.</param>
/// <param name="message">The message.</param>
public void Send(string messageQueueObjectName, Message message)
{
Send(MessageQueueFactory.CreateMessageQueue(messageQueueObjectName), message);
}
/// <summary>
/// Sends the specified message on the provided MessageQueue using the
/// transactional settings as dicted by MessageQueue's Transactional property and
/// the current Spring managed ambient transaction.
/// </summary>
/// <param name="messageQueue">The DefaultMessageQueue to send a message to.</param>
/// <param name="message">The message to send</param>
/// <para>
/// Note that it is the callers responsibility to ensure that the MessageQueue instance
/// passed into this not being access simultaneously by other threads.
/// </para>
/// <remarks>A transactional send (either local or DTC transaction) will be
/// attempted for a transacitonal queue, falling back to a single-transaction send
/// to a transactional queue if there is not ambient Spring managed transaction.</remarks>
public virtual void Send(MessageQueue messageQueue, Message message)
{
DoSend(messageQueue, message);
@@ -338,6 +428,13 @@ namespace Spring.Messaging.Core
#region Protected Methods
/// <summary>
/// Sends the message to the given message queue.
/// </summary>
/// <remarks>If System.Transactions.Transaction.Current is null, then send based on
/// the transaction semantics of the queue definition. See <see cref="DoSendMessageQueueTransactional"/> </remarks>
/// <param name="messageQueue">The message queue.</param>
/// <param name="message">The message.</param>
protected virtual void DoSend(MessageQueue messageQueue, Message message)
{
if (System.Transactions.Transaction.Current == null)
@@ -350,6 +447,34 @@ namespace Spring.Messaging.Core
}
}
/// <summary>
/// Send the message queue selecting the appropriate transactional delivery options.
/// </summary>
/// <remarks>
/// <para>
/// If the message queue is transactional and there is an ambient MessageQueueTransaction
/// in thread local storage (put there via the use of Spring's MessageQueueTransactionManager
/// or TransactionalMessageListenerContainer), the message will be sent transactionally using the
/// MessageQueueTransaction object in thread local storage. This lets you group together multiple
/// messaging operations within the same transaction without having to explicitly pass around the
/// MessageQueueTransaction object.
/// </para>
/// <para>
/// If the message queue is transactional but there is no ambient MessageQueueTransaction,
/// then a single message transaction is created on each messaging operation.
/// (MessageQueueTransactionType = Single).
/// </para>
/// <para>
/// If there is an ambient System.Transactions transaction then that transaction will
/// be used (MessageQueueTransactionType = Automatic).
/// </para>
/// <para>
/// If the queue is not transactional, then a non-transactional send
/// (MessageQueueTransactionType = None) is used.
/// </para>
/// </remarks>
/// <param name="mq">The mq.</param>
/// <param name="msg">The MSG.</param>
protected virtual void DoSendMessageQueueTransactional(MessageQueue mq, Message msg)
{
MessageQueueTransaction transactionToUse = QueueUtils.GetMessageQueueTransaction(null);
@@ -400,11 +525,21 @@ namespace Spring.Messaging.Core
}
/// <summary>
/// Sends using MessageQueueTransactionType.Automatic transaction type
/// </summary>
/// <param name="mq">The message queue.</param>
/// <param name="msg">The message.</param>
protected virtual void DoSendTxScope(MessageQueue mq, Message msg)
{
mq.Send(msg, MessageQueueTransactionType.Automatic);
}
/// <summary>
/// Template method to convert the message if it is not null.
/// </summary>
/// <param name="m">The message.</param>
/// <returns>The converted message ,or null if no message converter is set.</returns>
protected virtual object DoConvertMessage(Message m)
{
if (m != null)
@@ -417,6 +552,9 @@ namespace Spring.Messaging.Core
}
}
/// <summary>
/// Checks if the default message queue if defined.
/// </summary>
protected virtual void CheckDefaultMessageQueue()
{
if (DefaultMessageQueueObjectName == null)

View File

@@ -48,6 +48,9 @@ namespace Spring.Messaging.Core
/// <author>Mark Pollack</author>
public class MessageQueueTransactionManager : AbstractPlatformTransactionManager
{
/// <summary>
/// Location where the message transaction is stored in thread local storage.
/// </summary>
public static readonly string CURRENT_TRANSACTION_SLOTNAME =
UniqueKey.GetTypeScopedString(typeof (MessageQueueTransaction), "Current");
@@ -71,6 +74,16 @@ namespace Spring.Messaging.Core
TransactionSynchronization = TransactionSynchronizationState.Never;
}
/// <summary>
/// Return the current transaction object.
/// </summary>
/// <returns>The current transaction object.</returns>
/// <exception cref="Spring.Transaction.CannotCreateTransactionException">
/// If transaction support is not available.
/// </exception>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of lookup or system errors.
/// </exception>
protected override object DoGetTransaction()
{
MessageQueueTransactionObject txObject = new MessageQueueTransactionObject();
@@ -79,16 +92,33 @@ namespace Spring.Messaging.Core
return txObject;
}
/// <summary>
/// Check if the given transaction object indicates an existing transaction
/// (that is, a transaction which has already started).
/// </summary>
/// <param name="transaction">MessageQueueTransactionObject object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
/// <returns>
/// True if there is an existing transaction.
/// </returns>
protected override bool IsExistingTransaction(object transaction)
{
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction;
return (txObject.ResourceHolder != null);
}
/// <summary>
/// Begin a new transaction with the given transaction definition.
/// </summary>
/// <param name="transaction">Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
/// <param name="definition"><see cref="Spring.Transaction.ITransactionDefinition"/> instance, describing
/// propagation behavior, isolation level, timeout etc.</param>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of creation or system errors.
/// </exception>
protected override void DoBegin(object transaction, ITransactionDefinition definition)
{
//TODO check isolation level is different than default value?
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction;
MessageQueueTransaction mqt = new MessageQueueTransaction();
@@ -105,6 +135,15 @@ namespace Spring.Messaging.Core
TransactionSynchronizationManager.BindResource(CURRENT_TRANSACTION_SLOTNAME, txObject.ResourceHolder);
}
/// <summary>
/// Suspend the resources of the current transaction.
/// </summary>
/// <param name="transaction">Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
/// <returns>
/// An object that holds suspended resources (will be kept unexamined for passing it into
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoResume"/>.)
/// </returns>
protected override object DoSuspend(object transaction)
{
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction;
@@ -112,12 +151,28 @@ namespace Spring.Messaging.Core
return TransactionSynchronizationManager.UnbindResource(CURRENT_TRANSACTION_SLOTNAME);
}
/// <summary>
/// Resume the resources of the current transaction.
/// </summary>
/// <param name="transaction">Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
/// <param name="suspendedResources">The object that holds suspended resources as returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoSuspend"/>.</param>
protected override void DoResume(object transaction, object suspendedResources)
{
MessageQueueResourceHolder queueHolder = (MessageQueueResourceHolder) suspendedResources;
TransactionSynchronizationManager.BindResource(CURRENT_TRANSACTION_SLOTNAME, queueHolder);
}
/// <summary>
/// Perform an actual commit on the given transaction.
/// </summary>
/// <param name="status">The status representation of the transaction.</param>
/// <remarks>
/// <p>
/// An implementation does not need to check the rollback-only flag.
/// </p>
/// </remarks>
protected override void DoCommit(DefaultTransactionStatus status)
{
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction;
@@ -136,6 +191,13 @@ namespace Spring.Messaging.Core
}
}
/// <summary>
/// Perform an actual rollback on the given transaction, calls Transaction.Abort().
/// </summary>
/// <param name="status">The status representation of the transaction.</param>
/// <remarks>
/// An implementation does not need to check the new transaction flag.
/// </remarks>
protected override void DoRollback(DefaultTransactionStatus status)
{
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction;
@@ -154,12 +216,37 @@ namespace Spring.Messaging.Core
}
}
/// <summary>
/// Set the given transaction rollback-only. Only called on rollback
/// if the current transaction takes part in an existing one.
/// </summary>
/// <param name="status">The status representation of the transaction.</param>
/// <remarks>Default implementation throws an IllegalTransactionStateException,
/// assuming that participating in existing transactions is generally not
/// supported. Subclasses are of course encouraged to provide such support.
/// </remarks>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of system errors.
/// </exception>
protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
{
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) status.Transaction;
txObject.ResourceHolder.RollbackOnly = true;
}
/// <summary>
/// Cleanup resources after transaction completion.
/// </summary>
/// <param name="transaction">Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
/// <remarks>
/// <para>
/// Called after <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoCommit"/>
/// and
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoRollback"/>
/// execution on any outcome.
/// </para>
/// </remarks>
protected override void DoCleanupAfterCompletion(object transaction)
{
MessageQueueTransactionObject txObject = (MessageQueueTransactionObject) transaction;

View File

@@ -1,23 +0,0 @@
namespace Spring.Messaging.Core
{
public enum QueueIdentifierType
{
/// <summary>
/// Use a Label to identify the queue, for example new MessageQueue("Label:TheLabel");
/// </summary>
Label,
/// <summary>
/// Use a FormatName to idenitfy the queue,
/// </summary>
FormatName,
MachineName,
Path,
QueueName,
}
}

View File

@@ -152,6 +152,11 @@ namespace Spring.Messaging.Listener
#endregion
/// <summary>
/// Initializes this container. Calls the abstract method DoStart if the
/// property <see cref="AutoStartup"/> is set to true, then calls
/// <see cref="DoInitialize"/>
/// </summary>
public virtual void Initialize()
{
lock (lifecycleMonitor)
@@ -166,6 +171,10 @@ namespace Spring.Messaging.Listener
DoInitialize();
}
/// <summary>
/// Sets the container state to inactive and not running, calls template method
/// <see cref="DoShutdown"/>
/// </summary>
public virtual void Shutdown()
{
LOG.Debug("Shutting down MessageListenerContainer");
@@ -178,11 +187,17 @@ namespace Spring.Messaging.Listener
DoShutdown();
}
/// <summary>
/// Starts this container.
/// </summary>
public virtual void Start()
{
DoStart();
}
/// <summary>
/// Sets the state to running, can be overridden in subclasses.
/// </summary>
protected virtual void DoStart()
{
lock (lifecycleMonitor)
@@ -192,11 +207,17 @@ namespace Spring.Messaging.Listener
}
}
/// <summary>
/// Stops this instance.
/// </summary>
public virtual void Stop()
{
DoStop();
}
/// <summary>
/// Template method suitable for overriding that stops the container.
/// </summary>
public virtual void DoStop()
{
lock (lifecycleMonitor)

View File

@@ -158,6 +158,10 @@ namespace Spring.Messaging.Listener
#region Protected Methods
/// <summary>
/// Validates that the <see cref="messageQueueObjectName"/> is not null. If <see cref="MessageQueueFactory"/>
/// is null, a <see cref="DefaultMessageQueueFactory"/> is created. Can be be overridden in subclasses.
/// </summary>
protected override void ValidateConfiguration()
{
if (MessageQueueObjectName == null)
@@ -173,6 +177,14 @@ namespace Spring.Messaging.Listener
}
/// <summary>
/// Template method that execute listener with the provided message if
/// <see cref="AbstractListenerContainer.Running"/> is true. Subclasses will call
/// this method at the appropriate point in their processing lifecycle, for example
/// committing or rolling back a transaction if needed.
/// </summary>
/// <remarks>Calls the template method <see cref="InvokeListener"/></remarks>
/// <param name="message">The message.</param>
protected virtual void DoExecuteListener(Message message)
{
if (!Running)
@@ -187,6 +199,11 @@ namespace Spring.Messaging.Listener
InvokeListener(message);
}
/// <summary>
/// Invokes the listener if it is not null. Invokes the method <see cref="DoInvokeListener"/>.
/// Can be overridden in subclasses.
/// </summary>
/// <param name="message">The message.</param>
protected virtual void InvokeListener(Message message)
{
if (MessageListener != null)
@@ -199,6 +216,11 @@ namespace Spring.Messaging.Listener
}
}
/// <summary>
/// Invokes the listener. Can be overriden in subclasses.
/// </summary>
/// <param name="listener">The listener.</param>
/// <param name="message">The message.</param>
protected virtual void DoInvokeListener(IMessageListener listener, Message message)
{
listener.OnMessage(message);

View File

@@ -419,6 +419,11 @@ namespace Spring.Messaging.Listener
}
/// <summary>
/// Configures the initial peek thread, setting it to be a background thread.
/// Can be overridden in subclasses.
/// </summary>
/// <param name="thread">The peek thread.</param>
protected virtual void ConfigureInitialPeekThread(Thread thread)
{
thread.IsBackground = true;

View File

@@ -7,6 +7,14 @@ using Spring.Objects.Factory;
namespace Spring.Messaging.Listener
{
/// <summary>
/// Provides common functionality to exception handlers that will send the exceptional message to
/// another queue.
/// </summary>
/// <remarks>Allows for setting of MaxRetry limit and contains an internal dictionary to keep track
/// of the Message Ids of messages.
/// </remarks>
/// <author>Mark Pollack</author>
public class AbstractSendToQueueExceptionHandler : IInitializingObject, IApplicationContextAware
{
private int maxRetry = 5;
@@ -15,7 +23,15 @@ namespace Spring.Messaging.Listener
private string messageQueueObjectName;
private IApplicationContext applicationContext;
/// <summary>
/// Synchronization object for access to messageMap protected variable
/// </summary>
protected object messageMapMonitor = new object();
/// <summary>
/// In-memory storage to keep track of Message Ids that have been already processed.
/// </summary>
protected IDictionary messageMap = new Hashtable();
/// <summary>

View File

@@ -58,12 +58,20 @@ namespace Spring.Messaging.Listener
private DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
/// <summary>
/// Gets or sets the platform transaction manager.
/// </summary>
/// <value>The platform transaction manager.</value>
public IPlatformTransactionManager PlatformTransactionManager
{
get { return platformTransactionManager; }
set { platformTransactionManager = value; }
}
/// <summary>
/// Gets or sets the transaction definition.
/// </summary>
/// <value>The transaction definition.</value>
public DefaultTransactionDefinition TransactionDefinition
{
get { return transactionDefinition; }
@@ -80,6 +88,14 @@ namespace Spring.Messaging.Listener
set { transactionDefinition.TransactionTimeout = value; }
}
/// <summary>
/// Subclasses perform a receive opertion on the message queue and execute the
/// message listener
/// </summary>
/// <param name="mq">The DefaultMessageQueue.</param>
/// <returns>
/// true if received a message, false otherwise
/// </returns>
protected override bool DoReceiveAndExecute(MessageQueue mq)
{
bool messageReceived = false;
@@ -100,9 +116,20 @@ namespace Spring.Messaging.Listener
return messageReceived;
}
/// <summary>
/// Does the receive and execute using platform transaction manager.
/// </summary>
/// <param name="mq">The message queue.</param>
/// <param name="status">The transactional status.</param>
/// <returns>true if should continue peeking, false otherwise.</returns>
protected abstract bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq,
ITransactionStatus status);
/// <summary>
/// Rollback the transaction on exception.
/// </summary>
/// <param name="status">The transactional status.</param>
/// <param name="ex">The exception.</param>
protected void RollbackOnException(ITransactionStatus status, Exception ex)
{
LOG.Debug("Initiating transaction rollback on listener exception", ex);

View File

@@ -84,6 +84,15 @@ namespace Spring.Messaging.Listener
base.Initialize();
}
/// <summary>
/// Does the receive and execute using TxPlatformTransactionManager. Starts a distributed
/// transaction before calling Receive.
/// </summary>
/// <param name="mq">The message queue.</param>
/// <param name="status">The transactional status.</param>
/// <returns>
/// true if should continue peeking, false otherwise.
/// </returns>
protected override bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq,
ITransactionStatus status)
{
@@ -186,6 +195,12 @@ namespace Spring.Messaging.Listener
return true;
}
/// <summary>
/// Handles the distributed transaction listener exception by calling the
/// <see cref="IDistributedTransactionExceptionHandler"/> if not null.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="message">The message.</param>
protected virtual void HandleDistributedTransactionListenerException(Exception exception, Message message)
{
IDistributedTransactionExceptionHandler exceptionHandler = DistributedTransactionExceptionHandler;

View File

@@ -161,12 +161,28 @@ namespace Spring.Messaging.Listener
#endregion
/// <summary>
/// Gets or sets the handler object to delegate message listening to.
/// </summary>
/// <remarks>
/// Specified listener methods have to be present on this target object.
/// If no explicit handler object has been specified, listener
/// methods are expected to present on this adapter instance, that is,
/// on a custom subclass of this adapter, defining listener methods.
/// </remarks>
/// <value>The handler object.</value>
public object HandlerObject
{
get { return handlerObject; }
set { handlerObject = value; }
}
/// <summary>
/// Gets or sets the default handler method to delegate to,
/// for the case where no specific listener method has been determined.
/// Out-of-the-box value is "HandleMessage".
/// </summary>
/// <value>The default handler method.</value>
public string DefaultHandlerMethod
{
get { return defaultHandlerMethod; }
@@ -256,18 +272,42 @@ namespace Spring.Messaging.Listener
#endregion
/// <summary>
/// Gets or sets the message queue factory.
/// </summary>
/// <value>The message queue factory.</value>
public IMessageQueueFactory MessageQueueFactory
{
get { return messageQueueFactory; }
set { messageQueueFactory = value; }
}
/// <summary>
/// Sets the name of the default response queue to send response messages to.
/// This will be applied in case of a request message that does not carry a
/// "ResponseQueue" value.
/// <para>Alternatively, specify a response queue via the property
/// <see cref="DefaultResponseQueue"/>.</para>
/// </summary>
/// <value>The name of the default response destination queue.</value>
public string DefaultResponseQueueName
{
get { return defaultResponseQueueName; }
set { defaultResponseQueueName = value; }
}
/// <summary>
/// Sets the default destination to send response messages to. This will be applied
/// in case of a request message that does not carry a "ResponseQueue" property
/// Response destinations are only relevant for listener methods that return
/// result objects, which will be wrapped in a response message and sent to a
/// response destination.
/// <para>
/// Alternatively, specify a "DefaultResponseQueueName"
/// to be dynamically resolved via the MessageQueueFactory.
/// </para>
/// </summary>
/// <value>The default response destination.</value>
public MessageQueue DefaultResponseQueue
{
get
@@ -280,42 +320,36 @@ namespace Spring.Messaging.Listener
{
return null;
}
/*
DefaultMessageQueue mq = LogicalThreadContext.GetData(CURRENT_RESPONSEQUEUE_SLOTNAME) as DefaultMessageQueue;
if (mq == null)
{
mq = ApplicationContext.GetObject(DefaultResponseQueueName) as DefaultMessageQueue;
LogicalThreadContext.SetData(CURRENT_RESPONSEQUEUE_SLOTNAME, mq);
}
return mq;
*/
}
}
/// <summary>
/// Gets or sets the name of the message converter object used to resolved a <see cref="IMessageConverter"/>
/// instance.
/// </summary>
/// <value>The name of the message converter object.</value>
public string MessageConverterObjectName
{
get { return messageConverterObjectName; }
set { messageConverterObjectName = value; }
}
/// <summary>
/// Gets message converter that will convert incoming MSMQ messages to
/// listener method arguments, and objects returned from listener
/// methods back to MSMQ messages.
/// </summary>
/// <remarks>
/// <para>The converter used is the one returned by CreateMessageConverter on MessageQueueFactory.
/// </para>
/// </remarks>
/// <value>The message converter.</value>
public IMessageConverter MessageConverter
{
get
{
return messageQueueFactory.CreateMessageConverter(MessageConverterObjectName);
/*
if (messageConverter == null)
{
throw new InvalidOperationException("No MessageConverter registered. Check configuration of MessageQueueTemplate.");
}
IMessageConverter mc = LogicalThreadContext.GetData(CURRENT_CONVERTER_SLOTNAME) as IMessageConverter;
if (mc == null)
{
mc = messageConverter.Clone() as IMessageConverter;
LogicalThreadContext.SetData(CURRENT_CONVERTER_SLOTNAME, mc);
}
return mc;*/
}
}
@@ -366,6 +400,12 @@ namespace Spring.Messaging.Listener
messageQueueTemplate = new MessageQueueTemplate();
}
/// <summary>
/// Extracts the message body from the given message.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>the content of the message, to be passed into the
/// listener method as argument</returns>
protected virtual object ExtractMessage(Message message)
{
IMessageConverter converter = MessageConverter;
@@ -389,12 +429,23 @@ namespace Spring.Messaging.Listener
SendResponse(destination, response);
}
/// <summary>
/// Sends the given response message to the given destination.
/// </summary>
/// <param name="destination">The destination to send to.</param>
/// <param name="response">The outgoing message about to be sent.</param>
protected virtual void SendResponse(MessageQueue destination, Message response)
{
//Will send with appropriate transaction semantics
messageQueueTemplate.Send(destination, response);
}
/// <summary>
/// Builds a MSMQ message to be sent as response based on the given result object.
/// </summary>
/// <param name="result">The result.</param>
/// <returns>the MSMQ <code>Message</code> (never <code>null</code>)</returns>
/// <exception cref="MessagingException">If no messgae converter is specified.</exception>
protected virtual Message BuildMessage(object result)
{
IMessageConverter converter = MessageConverter;
@@ -421,11 +472,32 @@ namespace Spring.Messaging.Listener
}
}
/// <summary>
/// Post-process the given response message before it will be sent. The default implementation
/// sets the response's correlation id to the request message's correlation id.
/// </summary>
/// <param name="request">The original incoming message.</param>
/// <param name="response">The outgoing MSMQ message about to be sent.</param>
protected virtual void PostProcessResponse(Message request, Message response)
{
response.CorrelationId = request.CorrelationId;
}
/// <summary>
/// Determine a response destination for the given message.
/// </summary>
/// <remarks>
/// <para>The default implementation first checks the MSMQ ResponseQueue
/// of the supplied request; if that is not <code>null</code>
/// it is returned; if it is <code>null</code>, then the configured
/// <see cref="DefaultResponseQueue"/> default response destination}
/// is returned; if this too is <code>null</code>, then an
/// <see cref="MessagingException"/>is thrown.
/// </para>
/// </remarks>
/// <param name="request">The request.</param>
/// <param name="response">The response.</param>
/// <returns></returns>
protected virtual MessageQueue GetResponseDestination(Message request, Message response)
{
MessageQueue replyTo = request.ResponseQueue;

View File

@@ -32,6 +32,7 @@ namespace Spring.Messaging.Listener
/// Exceptions that occur during message processing are handled by an instance
/// of <see cref="IExceptionHandler"/>.
/// </remarks>
/// <author>Mark Pollack</author>
public class NonTransactionalMessageListenerContainer : AbstractPeekingMessageListenerContainer
{
#region Logging Definition
@@ -43,6 +44,10 @@ namespace Spring.Messaging.Listener
private IExceptionHandler exceptionHandler;
/// <summary>
/// Gets or sets the exception handler.
/// </summary>
/// <value>The exception handler.</value>
public IExceptionHandler ExceptionHandler
{
get { return exceptionHandler; }
@@ -50,6 +55,11 @@ namespace Spring.Messaging.Listener
}
/// <summary>
/// Handles the listener exception.
/// </summary>
/// <param name="e">The exception.</param>
/// <param name="message">The message delivered that resultd in an processing exception.</param>
protected virtual void HandleListenerException(Exception e, Message message)
{
IExceptionHandler exceptionHandler = ExceptionHandler;
@@ -59,6 +69,14 @@ namespace Spring.Messaging.Listener
}
}
/// <summary>
/// Perform a receive opertion on the message queue and execute the
/// message listener
/// </summary>
/// <param name="mq">The DefaultMessageQueue.</param>
/// <returns>
/// true if received a message, false otherwise
/// </returns>
protected override bool DoReceiveAndExecute(MessageQueue mq)
{
Message message = null;

View File

@@ -25,6 +25,13 @@ using Common.Logging;
namespace Spring.Messaging.Listener
{
/// <summary>
/// detects poison messages by tracking the Message Id property in memory with a count of how many
/// times an exception has occurred. If that count is greater than the handler's MaxRetry count it
/// will be sent to another queue. The queue to send the message to is specified via the property M
/// essageQueueObjectName.
/// </summary>
/// <remarks>Exception handler when using DistributedTxMessageListenerContainer</remarks>
public class SendToQueueDistributedTransactionExceptionHandler : AbstractSendToQueueExceptionHandler,
IDistributedTransactionExceptionHandler
{
@@ -37,6 +44,19 @@ namespace Spring.Messaging.Listener
#region IDistributedTransactionExceptionHandler Members
/// <summary>
/// Determines whether the incoming message is a poison message. This method is
/// called before the <see cref="IMessageListener"/> is invoked.
/// </summary>
/// <param name="message">The incoming message.</param>
/// <returns>
/// <c>true</c> if it is a poison message; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// The <see cref="DistributedTxMessageListenerContainer"/> will call
/// <see cref="HandlePoisonMessage"/> if this method returns true and will
/// then commit the distibuted transaction (removing the message from the queue).
/// </remarks>
public bool IsPoisonMessage(Message message)
{
string messageId = message.Id;
@@ -56,11 +76,20 @@ namespace Spring.Messaging.Listener
}
}
/// <summary>
/// Handles the poison message.
/// </summary>
/// <param name="message">The message.</param>
public void HandlePoisonMessage(Message message)
{
SendMessageToQueue(message);
}
/// <summary>
/// Called when an exception is thrown in listener processing.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="message">The message.</param>
public void OnException(Exception exception, Message message)
{
string messageId = message.Id;
@@ -84,6 +113,10 @@ namespace Spring.Messaging.Listener
#endregion
/// <summary>
/// Sends the message to queue.
/// </summary>
/// <param name="message">The message.</param>
protected virtual void SendMessageToQueue(Message message)
{
MessageQueue mq = MessageQueueFactory.CreateMessageQueue(MessageQueueObjectName);

View File

@@ -25,6 +25,12 @@ using Common.Logging;
namespace Spring.Messaging.Listener
{
/// <summary>
/// Keeps track of the Message's Id property in memory with a count of how many times an
/// exception has occurred. If that count is greater than the handler's MaxRetry count it
/// will be sent to another queue using the provided MessageQueueTransaction. The queue to
/// send the message to is specified via the property MessageQueueObjectName.
/// </summary>
public class SendToQueueExceptionHandler : AbstractSendToQueueExceptionHandler, IMessageTransactionExceptionHandler
{
#region Logging Definition
@@ -58,6 +64,17 @@ namespace Spring.Messaging.Listener
#region IMessageTransactionExceptionHandler Members
/// <summary>
/// Called when an exception is thrown during listener processing under the
/// scope of a <see cref="MessageQueueTransaction"/>.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="message">The message.</param>
/// <param name="messageQueueTransaction">The message queue transaction.</param>
/// <returns>
/// An action indicating if the caller should commit or rollback the
/// <see cref="MessageQueueTransaction"/>
/// </returns>
public TransactionAction OnException(Exception exception, Message message,
MessageQueueTransaction messageQueueTransaction)
{
@@ -100,6 +117,13 @@ namespace Spring.Messaging.Listener
#region Protected Methods
/// <summary>
/// Determines whether this exception was already processed.
/// </summary>
/// <param name="exception">The exception.</param>
/// <returns>
/// <c>true</c> if the exception was already processed; otherwise, <c>false</c>.
/// </returns>
protected virtual bool IsMessageAlreadyProcessedException(Exception exception)
{
if (MessageAlreadyProcessedExceptionNames != null)
@@ -115,6 +139,12 @@ namespace Spring.Messaging.Listener
return false;
}
/// <summary>
/// Sends the message to queue.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="messageQueueTransaction">The message queue transaction.</param>
/// <returns>TransactionAction.Commit</returns>
protected virtual TransactionAction SendMessageToQueue(Message message,
MessageQueueTransaction messageQueueTransaction)
{

View File

@@ -241,6 +241,14 @@ namespace Spring.Messaging.Listener
#region Protected Methods
/// <summary>
/// Does the receive and execute using platform transaction manager.
/// </summary>
/// <param name="mq">The message queue.</param>
/// <param name="status">The transactional status.</param>
/// <returns>
/// true if should continue peeking, false otherwise.
/// </returns>
protected override bool DoReceiveAndExecuteUsingPlatformTransactionManager(MessageQueue mq,
ITransactionStatus status)
{
@@ -273,6 +281,12 @@ namespace Spring.Messaging.Listener
throw new NotImplementedException("Try using NonTransactionalMessageListenerContainer instead.");
}
/// <summary>
/// Does the recieve and execute using message queue transaction manager.
/// </summary>
/// <param name="mq">The message queue.</param>
/// <param name="status">The transactional status.</param>
/// <returns>true if should continue peeking, false otherise</returns>
protected virtual bool DoRecieveAndExecuteUsingMessageQueueTransactionManager(MessageQueue mq,
ITransactionStatus status)
{
@@ -291,7 +305,6 @@ namespace Spring.Messaging.Listener
try
{
//TODO check that GetMessageQueueTransction doesn't return null.
message = mq.Receive(TimeSpan.Zero, QueueUtils.GetMessageQueueTransaction(null));
}
catch (MessageQueueException ex)
@@ -403,6 +416,12 @@ namespace Spring.Messaging.Listener
return true;
}
/// <summary>
/// Does the recieve and execute using a local MessageQueueTransaction.
/// </summary>
/// <param name="mq">The mqessage queue.</param>
/// <param name="status">The transactional status.</param>
/// <returns>true if should continue peeking, false otherwise.</returns>
protected virtual bool DoRecieveAndExecuteUsingResourceTransactionManagerWithTxQueue(MessageQueue mq,
ITransactionStatus status)
{
@@ -598,6 +617,13 @@ namespace Spring.Messaging.Listener
}
/// <summary>
/// Handles the transactional listener exception.
/// </summary>
/// <param name="e">The exception thrown while processing the message.</param>
/// <param name="message">The message.</param>
/// <param name="messageQueueTransaction">The message queue transaction.</param>
/// <returns>The TransactionAction retruned by the TransactionalExceptionListener</returns>
protected virtual TransactionAction HandleTransactionalListenerException(Exception e, Message message,
MessageQueueTransaction
messageQueueTransaction)
@@ -628,14 +654,22 @@ namespace Spring.Messaging.Listener
}
/// <summary>
/// Invokes the transactional exception listener.
/// </summary>
/// <param name="e">The exception thrown during message processing.</param>
/// <param name="message">The message.</param>
/// <param name="messageQueueTransaction">The message queue transaction.</param>
/// <returns>TransactionAction.Rollback if no exception handler is defined, otherwise the
/// TransactionAction returned by the exception handler</returns>
protected virtual TransactionAction InvokeTransactionalExceptionListener(Exception e, Message message,
MessageQueueTransaction
messageQueueTransaction)
{
IMessageTransactionExceptionHandler exMessageTransaction = MessageTransactionExceptionHandler;
if (exMessageTransaction != null)
IMessageTransactionExceptionHandler exceptionHandler = MessageTransactionExceptionHandler;
if (exceptionHandler != null)
{
return exMessageTransaction.OnException(e, message, messageQueueTransaction);
return exceptionHandler.OnException(e, message, messageQueueTransaction);
}
else
{

View File

@@ -3,6 +3,10 @@ using System.Runtime.Serialization;
namespace Spring.Messaging
{
/// <summary>
/// Base exception class for exceptions thrown by Spring in Spring.Messaging
/// </summary>
/// <author>Mark Pollack</author>
public class MessagingException : ApplicationException
{
#region Constructor (s) / Destructor

View File

@@ -18,22 +18,32 @@
#endregion
using System;
using System.Messaging;
namespace Spring.Messaging.Support.Converters
{
/// <summary>
/// An <see cref="IMessageConverter"/> implementation that delegates to an instance of
/// <see cref="ActiveXMessageFormatter"/> to convert messages.
/// </summary>
/// <author>Mark Pollack</author>
public class ActiveXMessageConverter : IMessageConverter
{
private ActiveXMessageFormatter messageFormatter;
private readonly ActiveXMessageFormatter messageFormatter;
/// <summary>
/// Initializes a new instance of the <see cref="ActiveXMessageConverter"/> class.
/// </summary>
public ActiveXMessageConverter()
{
messageFormatter = new ActiveXMessageFormatter();
}
/// <summary>
/// Initializes a new instance of the <see cref="ActiveXMessageConverter"/> class.
/// </summary>
/// <param name="messageFormatter">The message formatter.</param>
public ActiveXMessageConverter(ActiveXMessageFormatter messageFormatter)
{
this.messageFormatter = messageFormatter;
@@ -41,6 +51,11 @@ namespace Spring.Messaging.Support.Converters
#region IMessageConverter Members
/// <summary>
/// Convert the given object to a Message.
/// </summary>
/// <param name="obj">The object to send.</param>
/// <returns>Message to send</returns>
public Message ToMessage(object obj)
{
Message m = new Message();
@@ -49,6 +64,11 @@ namespace Spring.Messaging.Support.Converters
return m;
}
/// <summary>
/// Convert the given message to a object.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>the object</returns>
public object FromMessage(Message message)
{
message.Formatter = messageFormatter;
@@ -59,6 +79,12 @@ namespace Spring.Messaging.Support.Converters
#region ICloneable Members
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public object Clone()
{
ActiveXMessageConverter mc = new ActiveXMessageConverter(messageFormatter.Clone() as ActiveXMessageFormatter);

View File

@@ -18,44 +18,73 @@
#endregion
using System;
using System.Messaging;
using System.Runtime.Serialization.Formatters;
namespace Spring.Messaging.Support.Converters
{
/// <summary>
/// An <see cref="IMessageConverter"/> implementation that delegates to an instance of
/// <see cref="BinaryMessageFormatter"/> to convert messages.
/// </summary>
/// <author>Mark Pollack</author>
public class BinaryMessageConverter : IMessageConverter
{
private BinaryMessageFormatter binaryMessageFormatter;
private readonly BinaryMessageFormatter binaryMessageFormatter;
private FormatterTypeStyle typeFormat;
private FormatterAssemblyStyle topObjectFormat;
/// <summary>
/// Initializes a new instance of the <see cref="BinaryMessageConverter"/> class.
/// </summary>
public BinaryMessageConverter()
{
binaryMessageFormatter = new BinaryMessageFormatter();
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryMessageConverter"/> class.
/// </summary>
/// <param name="binaryMessageFormatter">The binary message formatter.</param>
public BinaryMessageConverter(BinaryMessageFormatter binaryMessageFormatter)
{
this.binaryMessageFormatter = binaryMessageFormatter;
this.binaryMessageFormatter = binaryMessageFormatter;
}
/// <summary>
/// Gets or sets the type format used in the <see cref="BinaryMessageFormatter"/>
/// </summary>
/// <value>The type format.</value>
public FormatterTypeStyle TypeFormat
{
get { return typeFormat; }
set { typeFormat = value; }
get
{
return binaryMessageFormatter.TypeFormat;
}
set {
binaryMessageFormatter.TypeFormat = value;
}
}
/// <summary>
/// Gets or sets the top object format used in the <see cref="BinaryMessageFormatter"/>
/// </summary>
/// <value>The top object format.</value>
public FormatterAssemblyStyle TopObjectFormat
{
get { return topObjectFormat; }
set { topObjectFormat = value; }
get { return binaryMessageFormatter.TopObjectFormat; }
set
{
binaryMessageFormatter.TopObjectFormat = value;
}
}
#region IMessageConverter Members
/// <summary>
/// Convert the given object to a Message using the <see cref="BinaryMessageFormatter"/>
/// </summary>
/// <param name="obj">The object to send.</param>
/// <returns>Message to send</returns>
public Message ToMessage(object obj)
{
Message m = new Message();
@@ -64,6 +93,11 @@ namespace Spring.Messaging.Support.Converters
return m;
}
/// <summary>
/// Convert the given message to a object using the <see cref="BinaryMessageFormatter"/>
/// </summary>
/// <param name="message">The message.</param>
/// <returns>the object</returns>
public object FromMessage(Message message)
{
message.Formatter = binaryMessageFormatter;
@@ -74,8 +108,15 @@ namespace Spring.Messaging.Support.Converters
#region ICloneable Members
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public object Clone()
{
//takes into account TypeFormat and TypeObjectFormat
BinaryMessageConverter mc = new BinaryMessageConverter(binaryMessageFormatter.Clone() as BinaryMessageFormatter);
return mc;
}

View File

@@ -23,6 +23,9 @@ using System.Messaging;
namespace Spring.Messaging.Support.Converters
{
/// <summary>
/// An interface specifying the contract to convert to and from <see cref="Message"/> objects.
/// </summary>
public interface IMessageConverter : ICloneable
{
/// <summary>

View File

@@ -1,4 +1,22 @@
#region License
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed 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.
*/
#endregion
using System;
using System.Messaging;
@@ -6,10 +24,20 @@ using System.Xml;
namespace Spring.Messaging.Support.Converters
{
/// <summary>
/// Converts an <see cref="XmlDocument"/> to a Message and vice-versa by using the message's
/// body stream.
/// </summary>
/// <author>Mark Pollack</author>
public class XmlDocumentConverter : IMessageConverter
{
#region IMessageConverter Members
/// <summary>
/// Convert the given object to a Message.
/// </summary>
/// <param name="obj">The object to send.</param>
/// <returns>Message to send</returns>
public Message ToMessage(object obj)
{
XmlDocument doc = obj as XmlDocument;
@@ -25,6 +53,11 @@ namespace Spring.Messaging.Support.Converters
}
}
/// <summary>
/// Convert the given message to a object.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>the object</returns>
public object FromMessage(Message message)
{
XmlDocument doc = new XmlDocument();
@@ -36,9 +69,15 @@ namespace Spring.Messaging.Support.Converters
#region ICloneable Members
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public object Clone()
{
throw new NotImplementedException();
return new XmlDocumentConverter();
}
#endregion

View File

@@ -25,20 +25,36 @@ using Spring.Util;
namespace Spring.Messaging.Support.Converters
{
/// <summary>
/// An <see cref="IMessageConverter"/> implementation that delegates to an instance of
/// <see cref="XmlMessageFormatter"/> to convert messages.
/// </summary>
/// <author>Mark Pollack</author>
public class XmlMessageConverter : IMessageConverter
{
private XmlMessageFormatter messageFormatter;
/// <summary>
/// Initializes a new instance of the <see cref="XmlMessageConverter"/> class.
/// </summary>
public XmlMessageConverter()
{
messageFormatter = new XmlMessageFormatter();
}
/// <summary>
/// Initializes a new instance of the <see cref="XmlMessageConverter"/> class.
/// </summary>
/// <param name="messageFormatter">The message formatter.</param>
public XmlMessageConverter(XmlMessageFormatter messageFormatter)
{
this.messageFormatter = messageFormatter;
}
/// <summary>
/// Gets or sets the target types used by the <see cref="XmlMessageFormatter"/>
/// </summary>
/// <value>The target types.</value>
public Type[] TargetTypes
{
set
@@ -49,6 +65,10 @@ namespace Spring.Messaging.Support.Converters
get { return messageFormatter.TargetTypes; }
}
/// <summary>
/// Gets or sets the target type names used by the <see cref="XmlMessageFormatter"/>
/// </summary>
/// <value>The target type names.</value>
public string[] TargetTypeNames
{
set
@@ -61,6 +81,11 @@ namespace Spring.Messaging.Support.Converters
#region IMessageConverter Members
/// <summary>
/// Convert the given object to a Message.
/// </summary>
/// <param name="obj">The object to send.</param>
/// <returns>Message to send</returns>
public Message ToMessage(object obj)
{
Message m = new Message();
@@ -69,6 +94,11 @@ namespace Spring.Messaging.Support.Converters
return m;
}
/// <summary>
/// Convert the given message to a object.
/// </summary>
/// <param name="message">The message.</param>
/// <returns>the object</returns>
public object FromMessage(Message message)
{
message.Formatter = messageFormatter;
@@ -79,6 +109,12 @@ namespace Spring.Messaging.Support.Converters
#region ICloneable Members
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
/// <returns>
/// A new object that is a copy of this instance.
/// </returns>
public object Clone()
{
XmlMessageConverter mc = new XmlMessageConverter(messageFormatter.Clone() as XmlMessageFormatter);

View File

@@ -28,6 +28,9 @@ using Spring.Transaction.Support;
namespace Spring.Messaging.Support
{
/// <summary>
/// Utility methods to support Spring's MSMQ functionality
/// </summary>
public class QueueUtils
{
@@ -54,6 +57,12 @@ namespace Spring.Messaging.Support
return messageConverterObjectName;
}
/// <summary>
/// Gets the message queue transaction from thread local storage
/// </summary>
/// <param name="resourceFactory">The resource factory.</param>
/// <returns>null if not found in thread local storage</returns>
public static MessageQueueTransaction GetMessageQueueTransaction(IResourceFactory resourceFactory)
{
MessageQueueResourceHolder resourceHolder =
@@ -64,25 +73,10 @@ namespace Spring.Messaging.Support
{
return resourceHolder.MessageQueueTransaction;
}
if (!TransactionSynchronizationManager.SynchronizationActive)
else
{
return null;
}
throw new NotImplementedException();
/*
MessageQueueResourceHolder resourceHolderToUse = resourceHolder;
if (resourceHolderToUse == null)
{
resourceHolderToUse = new MessageQueueResourceHolder(new MessageQueueTransaction());
}
if (resourceHolderToUse != resourceHolder)
{
TransactionSynchronizationManager.RegisterSynchronization(
new MessageQueueResourceSynchronization(resourceHolderToUse, resourceFactory.SynchedLocalTransactionAllowed));
resourceHolderToUse.SynchronizedWithTransaction = true;
TransactionSynchronizationManager.BindResource(MessageQueueTransactionManager.CURRENT_TRANSACTION_SLOTNAME, resourceHolderToUse);
}
return resourceHolderToUse.MessageQueueTransaction;*/
}
}
}
@@ -144,8 +138,18 @@ namespace Spring.Messaging.Support
#endregion
}
/// <summary> Callback interface for resource creation.
/// Serving as argument for the <code>GetMessageQueueTransaction</code> method.
/// </summary>
public interface IResourceFactory
{
/// <summary>
/// Return whether to allow for a local transaction that is synchronized with
/// a Spring-managed transaction (where the main transaction might be a ADO.NET-based
/// one for a specific IDbProvider, for example), with the MSMQ transaction
/// committing right after the main transaction.
/// Returns whether to allow for synchronizing a local MSMQ transaction
/// </summary>
bool SynchedLocalTransactionAllowed { get; }
}
}

View File

@@ -20,6 +20,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>Spring.Messaging.xml</DocumentationFile>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -52,7 +53,6 @@
<Compile Include="Messaging\Support\Converters\MessageConverterCreatorDelegate.cs" />
<Compile Include="Messaging\Core\DefaultMessageQueueFactory.cs" />
<Compile Include="Messaging\Support\MessageQueueCreatorDelegate.cs" />
<Compile Include="Messaging\Core\QueueIdentifierType.cs" />
<Compile Include="Messaging\Core\IMessageQueueFactory.cs" />
<Compile Include="Messaging\Core\MessagePostProcessorDelegate.cs" />
<Compile Include="Messaging\Listener\AbstractSendToQueueExceptionHandler.cs" />