diff --git a/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs b/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs
index a6c7b43d..329ad34b 100644
--- a/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs
+++ b/src/Spring/Spring.Messaging/Messaging/Core/DefaultMessageQueueFactory.cs
@@ -18,10 +18,11 @@
#endregion
-
+using System;
using System.Collections;
using System.Messaging;
using Spring.Context;
+using Spring.Messaging.Support;
using Spring.Messaging.Support.Converters;
using Spring.Threading;
using Spring.Util;
@@ -30,7 +31,8 @@ namespace Spring.Messaging.Core
{
///
/// A implementation that caches MessageQueue and IMessageConverter
- /// instances.
+ /// instances. The MessageQueue objects are created by retrieving them by-name from the
+ /// ApplicationContext.
///
/// Mark Pollack
public class DefaultMessageQueueFactory : IMessageQueueFactory, IApplicationContextAware
@@ -41,10 +43,18 @@ namespace Spring.Messaging.Core
private static readonly string CONVERTER_DICTIONARY_SLOTNAME =
UniqueKey.GetTypeScopedString(typeof (DefaultMessageQueueFactory), "Converter");
- private IApplicationContext applicationContext;
+ private IConfigurableApplicationContext applicationContext;
#region IMessageQueueFactory Members
+ public void RegisterMessageQueue(string messageQueueObjectName,
+ MessageQueueCreatorDelegate messageQueueCreatorDelegate)
+ {
+ MessageQueueFactoryObject mqfo = new MessageQueueFactoryObject();
+ mqfo.MessageCreatorDelegate = messageQueueCreatorDelegate;
+ applicationContext.ObjectFactory.RegisterSingleton(messageQueueObjectName, mqfo);
+ }
+
public MessageQueue CreateMessageQueue(string messageQueueObjectName)
{
AssertUtils.ArgumentHasText(messageQueueObjectName, "DefaultMessageQueueObjectName");
@@ -62,21 +72,40 @@ namespace Spring.Messaging.Core
return queues[messageQueueObjectName] as MessageQueue;
}
- public IMessageConverter CreateMessageConverter(string messgaeConverterObjectName)
+ public bool ContainsMessageQueue(string messageQueueObjectName)
{
- AssertUtils.ArgumentHasText(messgaeConverterObjectName, "MessgaeFormatterObjectName");
+ return applicationContext.ContainsObject(messageQueueObjectName);
+ }
+
+ public void RegisterMessageConverter(string messageConverterName,
+ MessageConverterCreatorDelegate messageConverterCreatorDelegate)
+ {
+ MessageConverterFactoryObject mcfo = new MessageConverterFactoryObject();
+ mcfo.MessageConverterCreatorDelegate = messageConverterCreatorDelegate;
+ applicationContext.ObjectFactory.RegisterSingleton(messageConverterName, mcfo);
+ }
+
+ public IMessageConverter CreateMessageConverter(string messageConverterObjectName)
+ {
+ AssertUtils.ArgumentHasText(messageConverterObjectName, "MessgaeFormatterObjectName");
IDictionary converters = LogicalThreadContext.GetData(CONVERTER_DICTIONARY_SLOTNAME) as IDictionary;
if (converters == null)
{
converters = new Hashtable();
LogicalThreadContext.SetData(CONVERTER_DICTIONARY_SLOTNAME, converters);
}
- if (!converters.Contains(messgaeConverterObjectName))
+ if (!converters.Contains(messageConverterObjectName))
{
- IMessageConverter mc = applicationContext.GetObject(messgaeConverterObjectName) as IMessageConverter;
- converters.Add(messgaeConverterObjectName, mc);
+ IMessageConverter mc = applicationContext.GetObject(messageConverterObjectName) as IMessageConverter;
+ converters.Add(messageConverterObjectName, mc);
}
- return converters[messgaeConverterObjectName] as IMessageConverter;
+ return converters[messageConverterObjectName] as IMessageConverter;
+ }
+
+
+ public bool ContainsMessageConverter(string messageConverterObjectName)
+ {
+ return applicationContext.ContainsObject(messageConverterObjectName);
}
#endregion
@@ -112,7 +141,18 @@ namespace Spring.Messaging.Core
public IApplicationContext ApplicationContext
{
get { return applicationContext; }
- set { applicationContext = value; }
+ set
+ {
+ AssertUtils.ArgumentNotNull(value, "An ApplicationContext instance is required");
+ IConfigurableApplicationContext ctx = value as IConfigurableApplicationContext;
+ if (ctx == null)
+ {
+ throw new InvalidOperationException(
+ "Implementations of IApplicationContext must also implement IConfigurableApplicationContext");
+ }
+
+ applicationContext = ctx;
+ }
}
#endregion
diff --git a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs
index 1326beba..6292b81b 100644
--- a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs
+++ b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueFactory.cs
@@ -19,23 +19,42 @@
#endregion
using System.Messaging;
+using Spring.Messaging.Support;
using Spring.Messaging.Support.Converters;
namespace Spring.Messaging.Core
{
///
- /// An interface for creating MessageQueue and IMessageConverter objects.
+ /// An interface for creating MessageQueue and IMessageConverter objects from object definitions
+ /// defined in the application context.
///
///
- /// These objects have methods that are generally not thread safe, (IMessageConverter classes
- /// rely on IMessageFormatter objects that are not thread safe). A major reason to
- /// for this interface is to provide thread-local instances such that appliation code need
- /// not be concerned with these resource management issues.
+ /// MessageQueue and IMessageConverter objects have methods that are generally not thread safe,
+ /// (IMessageConverter classes rely on IMessageFormatter objects that are not thread safe).
+ /// As such, a major reason to for this interface is to provide thread-local instances such that
+ /// appliation code need not be concerned with these resource management issues.
///
+ /// Mark Pollack
public interface IMessageQueueFactory
{
+ void RegisterMessageQueue(string messageQueueObjectName,
+ MessageQueueCreatorDelegate messageQueueCreatorDelegate);
+
MessageQueue CreateMessageQueue(string messageQueueObjectName);
+ bool ContainsMessageQueue(string messageQueueObjectName);
+
+
+
+ void RegisterMessageConverter(string messageConverterName,
+ MessageConverterCreatorDelegate MessageConverterCreatorDelegate);
+
+
IMessageConverter CreateMessageConverter(string messageConverterObjectName);
+
+ bool ContainsMessageConverter(string messageConverterObjectName);
+
+
+
}
}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs
index b28af25b..cee8b6ac 100644
--- a/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs
+++ b/src/Spring/Spring.Messaging/Messaging/Core/IMessageQueueOperations.cs
@@ -88,6 +88,11 @@ namespace Spring.Messaging.Core
/// if thrown by MSMQ API methods
void ConvertAndSend(string messageQueueObjectName, object obj, MessagePostProcessorDelegate messagePostProcessorDelegate);
+ /*
+ void ConvertAndSend(QueueIdentifierType queueIdentifierType, string destinationValue, string messageQueueObjectName, object obj);
+
+ void ConvertAndSend(QueueIdentifierType queueIdentifierType, string destinationValue, string messageQueueObjectName, object obj, MessagePostProcessorDelegate messagePostProcessorDelegate);
+ */
///
/// Receive and convert a message synchronously from the default message queue.
///
diff --git a/src/Spring/Spring.Messaging/Messaging/Core/QueueIdentifierType.cs b/src/Spring/Spring.Messaging/Messaging/Core/QueueIdentifierType.cs
new file mode 100644
index 00000000..11f41a81
--- /dev/null
+++ b/src/Spring/Spring.Messaging/Messaging/Core/QueueIdentifierType.cs
@@ -0,0 +1,23 @@
+
+
+namespace Spring.Messaging.Core
+{
+ public enum QueueIdentifierType
+ {
+ ///
+ /// Use a Label to identify the queue, for example new MessageQueue("Label:TheLabel");
+ ///
+ Label,
+
+ ///
+ /// Use a FormatName to idenitfy the queue,
+ ///
+ FormatName,
+
+ MachineName,
+
+ Path,
+
+ QueueName,
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs
new file mode 100644
index 00000000..bb9156e0
--- /dev/null
+++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterCreatorDelegate.cs
@@ -0,0 +1,31 @@
+#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 Spring.Messaging.Core;
+using Spring.Messaging.Support.Converters;
+
+namespace Spring.Messaging.Support.Converters
+{
+ ///
+ /// Delegate for creating IMessageConverter instance. Used by
+ /// to register a creation function with a given name.
+ ///
+ public delegate IMessageConverter MessageConverterCreatorDelegate();
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs
new file mode 100644
index 00000000..952afd8e
--- /dev/null
+++ b/src/Spring/Spring.Messaging/Messaging/Support/Converters/MessageConverterFactoryObject.cs
@@ -0,0 +1,80 @@
+#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 Spring.Objects.Factory.Config;
+
+namespace Spring.Messaging.Support.Converters
+{
+ ///
+ /// Internal class to that users can specify a delegate function to register with the application context that
+ /// will create a IMessageConverter instance easily at runtime.
+ ///
+ /// Mark Pollack
+ internal class MessageConverterFactoryObject : IConfigurableFactoryObject
+ {
+ private IObjectDefinition productTemplate;
+
+ private MessageConverterCreatorDelegate messageConverterCreatorDelegate;
+
+
+ public MessageConverterCreatorDelegate MessageConverterCreatorDelegate
+ {
+ get { return messageConverterCreatorDelegate; }
+ set { messageConverterCreatorDelegate = value; }
+ }
+
+ #region IConfigurableFactoryObject Members
+
+
+ ///
+ /// Gets the template object definition that should be used
+ /// to configure the instance of the object managed by this factory.
+ ///
+ /// The object definition to configure the factory's product
+ public IObjectDefinition ProductTemplate
+ {
+ get { return productTemplate; }
+ set { productTemplate = value; }
+ }
+
+ #endregion
+
+ #region IFactoryObject Members
+
+ public object GetObject()
+ {
+ return MessageConverterCreatorDelegate();
+ }
+
+ public Type ObjectType
+ {
+ get { return typeof(IMessageConverter); }
+ }
+
+ public bool IsSingleton
+ {
+ get { return false; }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs
new file mode 100644
index 00000000..2c530c5a
--- /dev/null
+++ b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueCreatorDelegate.cs
@@ -0,0 +1,13 @@
+
+
+using System.Messaging;
+using Spring.Messaging.Core;
+
+namespace Spring.Messaging.Support
+{
+ ///
+ /// Delegate for creating MessageQueue instance. Used by
+ /// to register a creation function with a given name.
+ ///
+ public delegate MessageQueue MessageQueueCreatorDelegate();
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs
index 10e7c149..209cc937 100644
--- a/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs
+++ b/src/Spring/Spring.Messaging/Messaging/Support/MessageQueueFactoryObject.cs
@@ -25,8 +25,13 @@ using Spring.Objects.Factory.Config;
namespace Spring.Messaging.Support
{
///
- /// Factory for creating MessageQueues
+ /// Factory for creating MessageQueues. This factory will create prototype instances, i.e. every call to GetObject
+ /// will return a new MessageQueue object.
///
+ /// All MessageQueue constructor arguments are exposed as properties of the factory object. As this
+ /// is a use the PropertyTemplate property to specify additional
+ /// configuration of the MessageQueue.
+ ///
/// Mark Pollack
public class MessageQueueFactoryObject : IConfigurableFactoryObject
{
@@ -45,7 +50,25 @@ namespace Spring.Messaging.Support
private bool messageReadPropertyFilterSetDefaults = false;
- //myQueue.MessageReadPropertyFilter.SetAll();
+ private MessageQueueCreatorDelegate messageCreatorDelegate;
+
+
+ ///
+ /// Gets or sets an instance of the MessageQueueCreator delegate that will be used to create the
+ /// MessageQueue object, instead of using the various public properties on this class such
+ /// as Path, AccessMode, etc. Not intended for end-users but rather as a means to help
+ /// register MessageQueueFactoryObject at runtime using convenience method on the IMessageQueueFactory.
+ ///
+ ///
+ /// Can also be specifed using an instance of MessageCreatorDelegate. If both are specifed, the
+ /// Interface implementation has priority.
+ ///
+ /// The function that is responsbile for creating a message queue.
+ public MessageQueueCreatorDelegate MessageCreatorDelegate
+ {
+ get { return messageCreatorDelegate; }
+ set { messageCreatorDelegate = value; }
+ }
///
/// Gets or sets the path used to creat DefaultMessageQueue instance.
@@ -139,17 +162,24 @@ namespace Spring.Messaging.Support
/// A newly configured MessageQueue object
public object GetObject()
{
- MessageQueue.EnableConnectionCache = enableConnectionCache;
- MessageQueue mq = new MessageQueue(Path, DenySharedReceive, EnableCache, AccessMode);
- if (messageReadPropertyFilterSetDefaults)
+ if (MessageCreatorDelegate != null)
{
- mq.MessageReadPropertyFilter.SetDefaults();
+ return MessageCreatorDelegate();
}
- if (messageReadPropertyFilterSetAll)
+ else
{
- mq.MessageReadPropertyFilter.SetAll();
+ MessageQueue.EnableConnectionCache = enableConnectionCache;
+ MessageQueue mq = new MessageQueue(Path, DenySharedReceive, EnableCache, AccessMode);
+ if (messageReadPropertyFilterSetDefaults)
+ {
+ mq.MessageReadPropertyFilter.SetDefaults();
+ }
+ if (messageReadPropertyFilterSetAll)
+ {
+ mq.MessageReadPropertyFilter.SetAll();
+ }
+ return mq;
}
- return mq;
}
///
diff --git a/src/Spring/Spring.Messaging/Spring.Messaging.2008.csproj b/src/Spring/Spring.Messaging/Spring.Messaging.2008.csproj
index 9e7833fa..4b774d0c 100644
--- a/src/Spring/Spring.Messaging/Spring.Messaging.2008.csproj
+++ b/src/Spring/Spring.Messaging/Spring.Messaging.2008.csproj
@@ -49,7 +49,10 @@
CommonAssemblyInfo.cs
+
+
+
@@ -78,6 +81,7 @@
+
diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs
index 07352779..2be48805 100644
--- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs
+++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.cs
@@ -21,6 +21,7 @@
#region Imports
using System;
+using System.Messaging;
using System.Transactions;
using NUnit.Framework;
using Spring.Data.Core;
@@ -43,7 +44,46 @@ namespace Spring.Messaging.Core
[TestFixture]
public class MessageQueueTemplateTests : AbstractDependencyInjectionSpringContextTests
{
- [Test]
+
+ [Test]
+ public void MessageCreator()
+ {
+ MessageQueueTemplate mqt = applicationContext["txqueue"] as MessageQueueTemplate;
+ Assert.IsNotNull(mqt);
+ string path = @".\Private$\mlptestqueue";
+ if (MessageQueue.Exists(path))
+ {
+ MessageQueue.Delete(path);
+ }
+ MessageQueue.Create(path, true);
+ mqt.MessageQueueFactory.RegisterMessageQueue("newQueueDefinition", delegate
+ {
+ MessageQueue mq = new MessageQueue();
+ mq.Path = path;
+ // other properties
+ return mq;
+ });
+
+ Assert.IsTrue(mqt.MessageQueueFactory.ContainsMessageQueue("newQueueDefinition"));
+
+ SendAndReceive("newQueueDefinition",mqt);
+
+ SimpleCreator sc = new SimpleCreator();
+ mqt.MessageQueueFactory.RegisterMessageQueue("fooQueueDefinition", sc.CreateQueue );
+
+ }
+
+ public class SimpleCreator
+ {
+ public MessageQueue CreateQueue()
+ {
+ return new MessageQueue();
+ }
+ }
+
+
+
+ [Test]
[ExpectedException(typeof (ArgumentException), ExpectedMessage = "DefaultMessageQueueObjectName is required.")]
public void NoMessageQueueNameSpecified()
{
@@ -86,12 +126,19 @@ namespace Spring.Messaging.Core
{
MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate;
Assert.IsNotNull(q);
- ReceiveHelloWorld(q,1);
+ ReceiveHelloWorld(null,q,1);
}
- private static void ReceiveHelloWorld(MessageQueueTemplate q, int index)
+ private static void ReceiveHelloWorld(string messageQueueObjectName, MessageQueueTemplate q, int index)
{
- object o = q.ReceiveAndConvert();
+ object o = null;
+ if (messageQueueObjectName == null)
+ {
+ o = q.ReceiveAndConvert();
+ } else
+ {
+ o = q.ReceiveAndConvert(messageQueueObjectName);
+ }
Assert.IsNotNull(o);
string data = o as string;
Assert.IsNotNull(data);
@@ -103,7 +150,7 @@ namespace Spring.Messaging.Core
{
MessageQueueTemplate q = applicationContext["queue"] as MessageQueueTemplate;
Assert.IsNotNull(q);
- SendAndRecieve(q);
+ SendAndReceive(q);
}
[Test]
@@ -111,7 +158,7 @@ namespace Spring.Messaging.Core
{
MessageQueueTemplate q = applicationContext["txqueue"] as MessageQueueTemplate;
Assert.IsNotNull(q);
- SendAndRecieve(q);
+ SendAndReceive(q);
}
[Test]
@@ -120,31 +167,44 @@ namespace Spring.Messaging.Core
MessageQueueTemplate q = applicationContext["txqueue"] as MessageQueueTemplate;
Assert.IsNotNull(q);
SendUsingMessageTxScope(q);
- Receive(q);
+ Receive(null,q);
}
- private static void SendAndRecieve(MessageQueueTemplate q)
+ private static void SendAndReceive(MessageQueueTemplate q)
{
- SendUsingMessageTx(q);
- Receive(q);
+ SendAndReceive(null, q);
}
- private static void Receive(MessageQueueTemplate q)
+ private static void SendAndReceive(string messageQueueObjectName, MessageQueueTemplate q)
{
- ReceiveHelloWorld(q,1);
- ReceiveHelloWorld(q,2);
- ReceiveHelloWorld(q,3);
+ SendUsingMessageTx(messageQueueObjectName, q);
+ Receive(messageQueueObjectName, q);
}
- private static void SendUsingMessageTx(MessageQueueTemplate q)
+ private static void Receive(string messageQueueObjectName, MessageQueueTemplate q)
+ {
+ ReceiveHelloWorld(messageQueueObjectName, q, 1);
+ ReceiveHelloWorld(messageQueueObjectName, q, 2);
+ ReceiveHelloWorld(messageQueueObjectName, q, 3);
+ }
+
+ private static void SendUsingMessageTx(string messageQueueObjectName, MessageQueueTemplate q)
{
IPlatformTransactionManager txManager = new MessageQueueTransactionManager();
TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);
transactionTemplate.Execute(delegate(ITransactionStatus status)
{
- q.ConvertAndSend("Hello World 1");
- q.ConvertAndSend("Hello World 2");
- q.ConvertAndSend("Hello World 3");
+ if (messageQueueObjectName == null)
+ {
+ q.ConvertAndSend("Hello World 1");
+ q.ConvertAndSend("Hello World 2");
+ q.ConvertAndSend("Hello World 3");
+ } else
+ {
+ q.ConvertAndSend(messageQueueObjectName, "Hello World 1");
+ q.ConvertAndSend(messageQueueObjectName, "Hello World 2");
+ q.ConvertAndSend(messageQueueObjectName, "Hello World 3");
+ }
return null;
});
}
diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml
index a69cc396..242c5866 100644
--- a/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml
+++ b/test/Spring/Spring.Messaging.Tests/Messaging/Core/MessageQueueTemplateTests.xml
@@ -34,18 +34,18 @@