diff --git a/lib/Net/2.0/Apache.NMS.dll b/lib/Net/2.0/Apache.NMS.dll
index b2369c8f..b5640841 100644
Binary files a/lib/Net/2.0/Apache.NMS.dll and b/lib/Net/2.0/Apache.NMS.dll differ
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs
new file mode 100644
index 00000000..b208587b
--- /dev/null
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs
@@ -0,0 +1,367 @@
+#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.Xml;
+using Apache.NMS;
+using Spring.Messaging.Nms.Listener;
+using Spring.Messaging.Nms.Listener.Adapter;
+using Spring.Objects.Factory.Config;
+using Spring.Objects.Factory.Support;
+using Spring.Objects.Factory.Xml;
+using Spring.Util;
+
+namespace Spring.Messaging.Nms.Config
+{
+ ///
+ /// Parser for the NMS <listener-container> element.
+ ///
+ /// Mark Fisher
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ public class MessageListenerContainerObjectDefinitionParser : IObjectDefinitionParser
+ {
+ #region Fields
+
+ private readonly string LISTENER_ELEMENT = "listener";
+
+ private readonly string ID_ATTRIBUTE = "id";
+
+ private readonly string DESTINATION_ATTRIBUTE = "destination";
+
+ private readonly string SUBSCRIPTION_ATTRIBUTE = "subscription";
+
+ private readonly string SELECTOR_ATTRIBUTE = "selector";
+
+ private readonly string REF_ATTRIBUTE = "ref";
+
+ private readonly string METHOD_ATTRIBUTE = "method";
+
+ private readonly string DESTINATION_RESOLVER_ATTRIBUTE = "destination-resolver";
+
+ private readonly string MESSAGE_CONVERTER_ATTRIBUTE = "message-converter";
+
+ private readonly string RESPONSE_DESTINATION_ATTRIBUTE = "response-destination";
+
+ private readonly string DESTINATION_TYPE_ATTRIBUTE = "destination-type";
+
+ private readonly string DESTINATION_TYPE_QUEUE = "queue";
+
+ private readonly string DESTINATION_TYPE_TOPIC = "topic";
+
+ private readonly string DESTINATION_TYPE_DURABLE_TOPIC = "durableTopic";
+
+ private readonly string CLIENT_ID_ATTRIBUTE = "client-id";
+
+ private readonly string ACKNOWLEDGE_ATTRIBUTE = "acknowledge";
+
+ private readonly string ACKNOWLEDGE_AUTO = "auto";
+
+ private readonly string ACKNOWLEDGE_CLIENT = "client";
+
+ private readonly string ACKNOWLEDGE_DUPS_OK = "dups-ok";
+
+ private readonly string ACKNOWLEDGE_TRANSACTED = "transacted";
+
+ private readonly string CONCURRENCY_ATTRIBUTE = "concurrency";
+
+ private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory";
+
+ #endregion
+
+ #region IObjectDefinitionParser Members
+
+ ///
+ /// Parse the specified XmlElement and register the resulting
+ /// ObjectDefinitions with the IObjectDefinitionRegistry
+ /// embedded in the supplied
+ ///
+ /// The element to be parsed.
+ /// TThe object encapsulating the current state of the parsing process.
+ /// Provides access to a IObjectDefinitionRegistry
+ /// The primary object definition.
+ ///
+ ///
+ /// This method is never invoked if the parser is namespace aware
+ /// and was called to process the root node.
+ ///
+ ///
+ public IObjectDefinition ParseElement(XmlElement element, ParserContext parserContext)
+ {
+
+ XmlNodeList childNodes = element.ChildNodes;
+ foreach (XmlNode childNode in childNodes)
+ {
+ if (childNode.NodeType == XmlNodeType.Element)
+ {
+ string localName = childNode.LocalName;
+ if (LISTENER_ELEMENT.Equals(localName))
+ {
+ ParseListener((XmlElement) childNode, element, parserContext);
+ }
+ }
+ }
+ return null;
+ }
+
+ #endregion
+
+ private void ParseListener(XmlElement listenerElement, XmlElement containerElement, ParserContext parserContext)
+ {
+ ObjectDefinitionBuilder listenerDefBuilder =
+ parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof (MessageListenerAdapter));
+
+ string reference = listenerElement.GetAttribute(REF_ATTRIBUTE);
+ if (!StringUtils.HasText(reference))
+ {
+ parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT,
+ "Listener '" + REF_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ listenerDefBuilder.AddPropertyValue("HandlerObject", new RuntimeObjectReference(reference));
+
+ string handlerMethod = null;
+ if (listenerElement.HasAttribute(METHOD_ATTRIBUTE))
+ {
+ handlerMethod = listenerElement.GetAttribute(METHOD_ATTRIBUTE);
+ {
+ if (!StringUtils.HasText(handlerMethod))
+ {
+ parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT,
+ "Listener '" + METHOD_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ }
+ }
+ listenerDefBuilder.AddPropertyValue("DefaultHandlerMethod", handlerMethod);
+
+ if (containerElement.HasAttribute(MESSAGE_CONVERTER_ATTRIBUTE))
+ {
+ string messageConverter = containerElement.GetAttribute(MESSAGE_CONVERTER_ATTRIBUTE);
+ listenerDefBuilder.AddPropertyValue("MessageConverter", new RuntimeObjectReference(messageConverter));
+ }
+
+ ObjectDefinitionBuilder containerDefBuilder = ParseContainer(listenerElement, containerElement, parserContext);
+
+ if (listenerElement.HasAttribute(RESPONSE_DESTINATION_ATTRIBUTE))
+ {
+ string responseDestination = listenerElement.GetAttribute(RESPONSE_DESTINATION_ATTRIBUTE);
+ bool pubSubDomain = IndicatesPubSub(containerDefBuilder.RawObjectDefinition);
+ listenerDefBuilder.AddPropertyValue(pubSubDomain ? "DefaultResponseTopicName" : "DefaultResponseQueueName",
+ responseDestination);
+ if (containerDefBuilder.RawObjectDefinition.PropertyValues.Contains("DestinationResolver"))
+ {
+ listenerDefBuilder.AddPropertyValue("DestinationResolver",
+ containerDefBuilder.RawObjectDefinition.PropertyValues.GetPropertyValue
+ (
+ "DestinationResolver").Value);
+ }
+ }
+
+ containerDefBuilder.AddPropertyValue("MessageListener", listenerDefBuilder.ObjectDefinition);
+
+ string containerObjectName = listenerElement.GetAttribute(ID_ATTRIBUTE);
+ // If no object id is given auto generate one using the ReaderContext's ObjectNameGenerator
+ if (!StringUtils.HasText(containerObjectName))
+ {
+ containerObjectName =
+ parserContext.ReaderContext.GenerateObjectName(containerDefBuilder.RawObjectDefinition);
+ }
+
+ parserContext.Registry.RegisterObjectDefinition(containerObjectName, containerDefBuilder.ObjectDefinition);
+ }
+
+ private ObjectDefinitionBuilder ParseContainer(XmlElement listenerElement, XmlElement containerElement,
+ ParserContext parserContext)
+ {
+ //Only support SimpleMessageListenerContainer
+ ObjectDefinitionBuilder containerDef =
+ parserContext.ParserHelper.CreateRootObjectDefinitionBuilder(typeof (SimpleMessageListenerContainer));
+
+ ParseListenerConfiguration(listenerElement, parserContext, containerDef);
+ ParseContainerConfiguration(containerElement, parserContext, containerDef);
+
+ string connectionFactoryObjectName = "connectionFactory";
+ if (containerElement.HasAttribute(CONNECTION_FACTORY_ATTRIBUTE))
+ {
+ connectionFactoryObjectName = containerElement.GetAttribute(CONNECTION_FACTORY_ATTRIBUTE);
+ if (!StringUtils.HasText(connectionFactoryObjectName))
+ {
+ parserContext.ReaderContext.ReportException(listenerElement, LISTENER_ELEMENT,
+ "Listener container '" + CONNECTION_FACTORY_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ }
+
+ containerDef.AddPropertyValue("ConnectionFactory", new RuntimeObjectReference(connectionFactoryObjectName));
+
+ string destinationResolverBeanName = containerElement.GetAttribute(DESTINATION_RESOLVER_ATTRIBUTE);
+ if (StringUtils.HasText(destinationResolverBeanName))
+ {
+ containerDef.AddPropertyValue("DestinationResolver",
+ new RuntimeObjectReference(destinationResolverBeanName));
+ }
+
+ string acknowledge = containerElement.GetAttribute(ACKNOWLEDGE_ATTRIBUTE);
+ if (StringUtils.HasText(acknowledge))
+ {
+ AcknowledgementMode acknowledgementMode = ParseAcknowledgementMode(containerElement, parserContext);
+ containerDef.AddPropertyValue("SessionAcknowledgeMode", acknowledgementMode);
+ }
+
+ int[] concurrency = ParseConcurrency(containerElement, parserContext);
+ if (concurrency != null)
+ {
+ containerDef.AddPropertyValue("ConcurrentConsumers", concurrency[1]);
+ }
+
+ return containerDef;
+ }
+
+ private bool IndicatesPubSub(AbstractObjectDefinition configDef)
+ {
+ return (bool) configDef.PropertyValues.GetPropertyValue("PubSubDomain").Value;
+ }
+
+ private void ParseListenerConfiguration(XmlElement ele, ParserContext parserContext,
+ ObjectDefinitionBuilder containerDef)
+ {
+ string destination = ele.GetAttribute(DESTINATION_ATTRIBUTE);
+ if (!StringUtils.HasText(destination))
+ {
+ parserContext.ReaderContext.ReportException(ele, LISTENER_ELEMENT,
+ "Listener '" + DESTINATION_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ containerDef.AddPropertyValue("DestinationName", destination);
+
+ if (ele.HasAttribute(SUBSCRIPTION_ATTRIBUTE))
+ {
+ string subscription = ele.GetAttribute(SUBSCRIPTION_ATTRIBUTE);
+ if (!StringUtils.HasText(subscription))
+ {
+ parserContext.ReaderContext.ReportException(ele, SUBSCRIPTION_ATTRIBUTE,
+ "Listener '" + SUBSCRIPTION_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ containerDef.AddPropertyValue("DurableSubscriptionName", subscription);
+ }
+
+ if (ele.HasAttribute(SELECTOR_ATTRIBUTE))
+ {
+ string selector = ele.GetAttribute(SELECTOR_ATTRIBUTE);
+ if (!StringUtils.HasText(selector))
+ {
+ parserContext.ReaderContext.ReportException(ele, selector,
+ "Listener '" + SELECTOR_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ containerDef.AddPropertyValue("MessageSelector", selector);
+ }
+ }
+
+ private void ParseContainerConfiguration(XmlElement ele, ParserContext parserContext,
+ ObjectDefinitionBuilder containerDef)
+ {
+ string destinationType = ele.GetAttribute(DESTINATION_TYPE_ATTRIBUTE);
+ bool pubSubDomain = false;
+ bool subscriptionDurable = false;
+ if (DESTINATION_TYPE_DURABLE_TOPIC.Equals(destinationType))
+ {
+ pubSubDomain = true;
+ subscriptionDurable = true;
+ }
+ else if (DESTINATION_TYPE_TOPIC.Equals(destinationType))
+ {
+ pubSubDomain = true;
+ }
+ else if ("".Equals(destinationType) || DESTINATION_TYPE_QUEUE.Equals(destinationType))
+ {
+ // the default: queue
+ }
+ else
+ {
+ parserContext.ReaderContext.ReportException(ele, destinationType,
+ "Invalid listener container '" + DESTINATION_TYPE_ATTRIBUTE +
+ "': only 'queue', 'topic' and 'durableTopic' supported");
+ }
+
+ containerDef.AddPropertyValue("PubSubDomain", pubSubDomain);
+ containerDef.AddPropertyValue("SubscriptionDurable", subscriptionDurable);
+
+ if (ele.HasAttribute(CLIENT_ID_ATTRIBUTE))
+ {
+ string clientId = ele.GetAttribute(CLIENT_ID_ATTRIBUTE);
+ if (!StringUtils.HasText(clientId))
+ {
+ parserContext.ReaderContext.ReportException(ele, clientId,
+ "Listener '" + CLIENT_ID_ATTRIBUTE +
+ "' attribute contains empty value.");
+ }
+ containerDef.AddPropertyValue("ClientId", clientId);
+ }
+ }
+
+ private AcknowledgementMode ParseAcknowledgementMode(XmlElement element, ParserContext parserContext)
+ {
+ string acknowledge = element.GetAttribute(ACKNOWLEDGE_ATTRIBUTE);
+ if (acknowledge.Equals(ACKNOWLEDGE_TRANSACTED))
+ {
+ return AcknowledgementMode.Transactional;
+ }
+ else if (acknowledge.Equals(ACKNOWLEDGE_DUPS_OK))
+ {
+ return AcknowledgementMode.DupsOkAcknowledge;
+ }
+ else if (acknowledge.Equals(ACKNOWLEDGE_CLIENT))
+ {
+ return AcknowledgementMode.ClientAcknowledge;
+ }
+ else if (!acknowledge.Equals(ACKNOWLEDGE_AUTO))
+ {
+ parserContext.ReaderContext.ReportException(element, ACKNOWLEDGE_ATTRIBUTE,
+ "Invalid listener container 'acknowledge' setting ['" +
+ acknowledge +
+ "]: only \"auto\", \"client\", \"dups-ok\" and \"transacted\" supported.");
+ }
+ return AcknowledgementMode.AutoAcknowledge;
+ }
+
+ private int[] ParseConcurrency(XmlElement ele, ParserContext parserContext)
+ {
+ String concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE);
+ if (!StringUtils.HasText(concurrency))
+ {
+ return null;
+ }
+ try
+ {
+ return new int[] {1, Int32.Parse(concurrency)};
+ }
+ catch (FormatException ex)
+ {
+ parserContext.ReaderContext.ReportException(ele, CONCURRENCY_ATTRIBUTE,
+ "Invalid concurrency value [" + concurrency + "]: only " +
+ "integer (e.g. \"5\") values upported.", ex);
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs
new file mode 100644
index 00000000..bb816be4
--- /dev/null
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/NmsNamespaceParser.cs
@@ -0,0 +1,49 @@
+#region License
+
+/*
+ * Copyright 2002-2007 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.Xml;
+
+namespace Spring.Messaging.Nms.Config
+{
+ ///
+ /// Namespace parser for the nms namespace.
+ ///
+ /// Mark Fisher
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ [
+ NamespaceParser(
+ Namespace = "http://www.springframework.net/nms",
+ SchemaLocationAssemblyHint = typeof (NmsNamespaceParser),
+ SchemaLocation = "/Spring.Messaging.Nms.Config/spring-nms-1.2.xsd"
+ )
+ ]
+ public class NmsNamespaceParser : NamespaceParserSupport
+ {
+ ///
+ /// Register a MessageListenerContainer for the 'listener-container' tag.
+ ///
+ public override void Init()
+ {
+ RegisterObjectDefinitionParser("listener-container", new MessageListenerContainerObjectDefinitionParser());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd
new file mode 100644
index 00000000..135f13f4
--- /dev/null
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/spring-nms-1.2.xsd
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs
index bddc8616..db145f65 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs
@@ -382,10 +382,10 @@ namespace Spring.Messaging.Nms.Connections
/// the wrapped connection
protected virtual IConnection GetSharedConnection(IConnection target)
{
- lock (connectionMonitor)
+ lock (connectionMonitor)
{
- return new CloseSupressingConnection(this, target);
- }
+ return new CloseSupressingConnection(this, target);
+ }
}
}
@@ -461,7 +461,7 @@ namespace Spring.Messaging.Nms.Connections
{
return session;
}
- return target.CreateSession();
+ return target.CreateSession(acknowledgementMode);
}
#region Pass through implementations to the target connection
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/IMessageOperations.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/IMessageOperations.cs
index 68831c83..0547cd36 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/IMessageOperations.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/IMessageOperations.cs
@@ -52,6 +52,20 @@ namespace Spring.Messaging.Nms
///
/// NMSException if there is any problem
object Execute(ISessionCallback action);
+
+ /// Execute the action specified by the given action object within
+ /// a NMS Session.
+ ///
+ ///
+ /// Note that the value of PubSubDomain affects the behavior of this method.
+ /// If PubSubDomain equals true, then a Session is passed to the callback.
+ /// If false, then a ISession is passed to the callback.b
+ ///
+ /// delegate that exposes the session
+ /// the result object from working with the session
+ ///
+ /// NMSException if there is any problem
+ object Execute(SessionDelegate del);
/// Send a message to a NMS destination. The callback gives access to
/// the NMS session and MessageProducer in order to do more complex
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/ISessionCallback.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/ISessionCallback.cs
index 447e1f89..e9510531 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/ISessionCallback.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/ISessionCallback.cs
@@ -26,8 +26,9 @@ namespace Spring.Messaging.Nms
/// Session
///
///
- ///
To be used with the MessageTemplate.Execute(ISessionCallback)}
- /// method, often implemented as an anonymous inner class.
+ /// To be used with the MessageTemplate.Execute(ISessionCallback)}
+ /// method. See for the equivalent callback
+ /// that can be used as a (anonymous) delegate.
///
/// Mark Pollack
///
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs
index ae3c7855..ec093e5a 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs
@@ -24,7 +24,7 @@ using Common.Logging;
using Spring.Context;
using Spring.Messaging.Nms.Connections;
using Spring.Messaging.Nms.Support;
-using Spring.Messaging.Nms.Support.IDestinations;
+using Spring.Messaging.Nms.Support.Destinations;
using Spring.Objects.Factory;
namespace Spring.Messaging.Nms.Listener
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs
new file mode 100644
index 00000000..d114aea7
--- /dev/null
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/ListenerExecutionFailedException.cs
@@ -0,0 +1,53 @@
+#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 Apache.NMS;
+
+namespace Spring.Messaging.Nms.Listener.Adapter
+{
+ ///
+ /// Exception to be thrown when the execution of a listener method failed.
+ ///
+ /// Juergen Hoeller
+ /// Mark Pollack (.NET)
+ public class ListenerExecutionFailedException : NMSException
+ {
+
+ ///
+ /// Initializes a new instance of the class, with the specified message
+ ///
+ /// The message.
+ public ListenerExecutionFailedException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class, with the specified message
+ /// and root cause exception
+ ///
+ /// The message.
+ /// The inner exception.
+ public ListenerExecutionFailedException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs
index fe8b18a6..506958ed 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/Adapter/MessageListenerAdapter.cs
@@ -1,11 +1,33 @@
+#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.Collections;
+using System.Reflection;
using Common.Logging;
using Spring.Expressions;
using Spring.Messaging.Nms.Listener;
using Spring.Messaging.Nms.Support;
using Spring.Messaging.Nms.Support.Converter;
-using Spring.Messaging.Nms.Support.IDestinations;
+using Spring.Messaging.Nms.Support.Destinations;
using Spring.Util;
using Apache.NMS;
@@ -146,7 +168,7 @@ namespace Spring.Messaging.Nms.Listener.Adapter
/// Alternatively, specify a JMS Destination object as "defaultResponseDestination".
///
/// The name of the default response destination queue.
- public string DefaultResponseDestinationQueueName
+ public string DefaultResponseQueueName
{
set { defaultResponseDestination = new DestinationNameHolder(value, false); }
}
@@ -158,7 +180,7 @@ namespace Spring.Messaging.Nms.Listener.Adapter
/// Alternatively, specify a JMS Destination object as "defaultResponseDestination".
///
/// The name of the default response destination topic.
- public string DefaultResponseDestinationTopicName
+ public string DefaultResponseTopicName
{
set { defaultResponseDestination = new DestinationNameHolder(value, true); }
}
@@ -238,6 +260,29 @@ namespace Spring.Messaging.Nms.Listener.Adapter
/// The session to operate on.
public void OnMessage(IMessage message, ISession session)
{
+ if (handlerObject != this)
+ {
+ if (typeof(ISessionAwareMessageListener).IsInstanceOfType(handlerObject))
+ {
+ if (session != null)
+ {
+ ((ISessionAwareMessageListener) handlerObject).OnMessage(message, session);
+ return;
+ }
+ else if (!typeof(IMessageListener).IsInstanceOfType(handlerObject))
+ {
+ throw new InvalidOperationException("MessageListenerAdapter cannot handle a " +
+ "SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself");
+ }
+ }
+ if (typeof(IMessageListener).IsInstanceOfType(handlerObject))
+ {
+ ((IMessageListener)handlerObject).OnMessage(message);
+ return;
+ }
+ }
+
+ // Regular case: find a handler method reflectively.
object convertedMessage = ExtractMessage(message);
@@ -250,7 +295,34 @@ namespace Spring.Messaging.Nms.Listener.Adapter
processingExpression = Expression.Parse(defaultHandlerMethod + "(#convertedObject)");
//Invoke message handler method and get result.
- object result = processingExpression.GetValue(handlerObject, vars);
+ object result;
+ try
+ {
+ result = processingExpression.GetValue(handlerObject, vars);
+ }
+ catch (NMSException)
+ {
+ throw;
+ }
+ // Will only happen if dynamic method invocation falls back to standard reflection.
+ catch (TargetInvocationException ex)
+ {
+ Exception targetEx = ex.InnerException;
+ if (ObjectUtils.IsAssignable(typeof(NMSException), targetEx))
+ {
+ throw ReflectionUtils.UnwrapTargetInvocationException(ex);
+ }
+ else
+ {
+ throw new ListenerExecutionFailedException("Listener method '" + defaultHandlerMethod + "' threw exception", targetEx);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ListenerExecutionFailedException("Failed to invoke target method '" + defaultHandlerMethod +
+ "' with argument " + convertedMessage, ex);
+ }
+
if (result != null)
{
HandleResult(result, message, session);
@@ -478,9 +550,9 @@ namespace Spring.Messaging.Nms.Listener.Adapter
///
internal class DestinationNameHolder
{
- private string name;
+ private readonly string name;
- private bool isTopic;
+ private readonly bool isTopic;
public DestinationNameHolder(string name, bool isTopic)
{
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs
index 6b93ce32..bb36b694 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs
@@ -223,6 +223,7 @@ namespace Spring.Messaging.Nms.Listener
SimpleMessageListener listener = new SimpleMessageListener(this, session);
+ // put in explicit registration with 'new' for compilation on .NET 1.1
consumer.Listener += new Apache.NMS.MessageListener(listener.OnMessage);
return consumer;
}
diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/MessageTemplate.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/MessageTemplate.cs
index b8d687a0..9f29a2f8 100644
--- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/MessageTemplate.cs
+++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/MessageTemplate.cs
@@ -23,7 +23,7 @@ using Common.Logging;
using Spring.Messaging.Nms.Connections;
using Spring.Messaging.Nms.Support;
using Spring.Messaging.Nms.Support.Converter;
-using Spring.Messaging.Nms.Support.IDestinations;
+using Spring.Messaging.Nms.Support.Destinations;
using Spring.Transaction.Support;
using Spring.Util;
using Apache.NMS;
@@ -581,6 +581,25 @@ namespace Spring.Messaging.Nms
#region IMessageOperations Implementation
+ ///
+ /// Execute the action specified by the given action object within
+ /// a NMS Session.
+ ///
+ /// delegate that exposes the session
+ ///
+ /// the result object from working with the session
+ ///
+ ///
+ /// Note that the value of PubSubDomain affects the behavior of this method.
+ /// If PubSubDomain equals true, then a Session is passed to the callback.
+ /// If false, then a ISession is passed to the callback.b
+ ///
+ /// NMSException if there is any problem
+ public object Execute(SessionDelegate del)
+ {
+ return Execute(new ExecuteSessionCallbackUsingDelegate(del));
+ }
+
/// Execute the action specified by the given action object within
/// a NMS Session.
///