From a79d4769dc8e93c6a753d94be020ae611185cd7d Mon Sep 17 00:00:00 2001 From: markpollack Date: Mon, 11 Aug 2008 21:20:03 +0000 Subject: [PATCH] Add reconnection logic to SimpleMessageListenerContainer. Test for SimpleMessageListenerContainer's ExceptionListener being invoked (SPRNET-542) --- ...ListenerContainerObjectDefinitionParser.cs | 50 +++++- .../Messaging/Nms/Config/spring-nms-1.2.xsd | 19 +++ .../Connections/SingleConnectionFactory.cs | 54 +++--- .../Nms/Listener/AbstractListenerContainer.cs | 20 +-- .../AbstractMessageListenerContainer.cs | 5 +- .../Listener/RecoveryTimeExceededException.cs | 53 ++++++ .../SimpleMessageListenerContainer.cs | 101 ++++++++++- .../Spring.Messaging.Nms.2005.csproj | 1 + .../SimpleMessageListenerContainerTests.cs | 159 ++++++++++++++++++ .../SimpleMessageListenerContainerTests.cs | 2 +- .../Messaging/Nms/StubQueue.cs | 64 +++++++ .../Spring.Messaging.Nms.Tests.2005.csproj | 2 + 12 files changed, 465 insertions(+), 65 deletions(-) create mode 100644 src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs create mode 100644 test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs create mode 100644 test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs index b208587b..84dd7586 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Config/MessageListenerContainerObjectDefinitionParser.cs @@ -21,6 +21,7 @@ using System; using System.Xml; using Apache.NMS; +using Spring.Core.TypeConversion; using Spring.Messaging.Nms.Listener; using Spring.Messaging.Nms.Listener.Adapter; using Spring.Objects.Factory.Config; @@ -82,8 +83,12 @@ namespace Spring.Messaging.Nms.Config private readonly string CONCURRENCY_ATTRIBUTE = "concurrency"; - private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory"; + private readonly string RECOVERY_INTERVAL_ATTRIBUTE = "recovery-interval"; + private readonly string MAX_RECOVERY_INTERVAL_ATTRIBUTE = "max-recovery-interval"; + + private readonly string CONNECTION_FACTORY_ATTRIBUTE = "connection-factory"; + #endregion #region IObjectDefinitionParser Members @@ -231,6 +236,9 @@ namespace Spring.Messaging.Nms.Config { containerDef.AddPropertyValue("ConcurrentConsumers", concurrency[1]); } + containerDef.AddPropertyValue("RecoveryInterval", ParseRecoveryInterval(containerElement, parserContext)); + + containerDef.AddPropertyValue("MaxRecoveryTime", ParseMaxRecoveryTime(containerElement, parserContext)); return containerDef; } @@ -346,7 +354,7 @@ namespace Spring.Messaging.Nms.Config private int[] ParseConcurrency(XmlElement ele, ParserContext parserContext) { - String concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE); + string concurrency = ele.GetAttribute(CONCURRENCY_ATTRIBUTE); if (!StringUtils.HasText(concurrency)) { return null; @@ -363,5 +371,43 @@ namespace Spring.Messaging.Nms.Config return null; } } + + private TimeSpan ParseRecoveryInterval(XmlElement ele, ParserContext parserContext) + { + string recoveryInterval = ele.GetAttribute(RECOVERY_INTERVAL_ATTRIBUTE); + if (!StringUtils.HasText(recoveryInterval)) + { + return SimpleMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL; + } + try + { + TimeSpanConverter tsc = new TimeSpanConverter(); + return (TimeSpan)tsc.ConvertFrom(recoveryInterval); + } catch (Exception ex) + { + parserContext.ReaderContext.ReportException(ele, RECOVERY_INTERVAL_ATTRIBUTE, + "Invalid recovery-interval value [" + recoveryInterval + "]", ex); + return SimpleMessageListenerContainer.DEFAULT_RECOVERY_INTERVAL; + } + } + private TimeSpan ParseMaxRecoveryTime(XmlElement ele, ParserContext parserContext) + { + string recoverTime = ele.GetAttribute(MAX_RECOVERY_INTERVAL_ATTRIBUTE); + if (!StringUtils.HasText(recoverTime)) + { + return SimpleMessageListenerContainer.DEFAULT_MAX_RECOVERY_TIME; + } + try + { + TimeSpanConverter tsc = new TimeSpanConverter(); + return (TimeSpan)tsc.ConvertFrom(recoverTime); + } + catch (Exception ex) + { + parserContext.ReaderContext.ReportException(ele, MAX_RECOVERY_INTERVAL_ATTRIBUTE, + "Invalid max-recovery-time value [" + recoverTime + "]", ex); + return SimpleMessageListenerContainer.DEFAULT_MAX_RECOVERY_TIME; + } + } } } \ 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 index 3aabc1d6..1d1b0be3 100644 --- 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 @@ -114,6 +114,25 @@ ]]> + + + + + + + + + + + + + + + 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 52aefe30..773357d0 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Connections/SingleConnectionFactory.cs @@ -35,11 +35,15 @@ namespace Spring.Messaging.Nms.Connections /// details. /// /// + /// /// You can either pass in a specific Connection directly or let this /// factory lazily create a Connection via a given target ConnectionFactory. - /// Useful in order to keep using the same Connection for multiple - /// calls, without having a pooling ConnectionFactory - /// underneath. This may span any number of transactions, even concurrently executing transactions. + /// + /// + /// Useful for testing and in applications when you want to keep using the + /// same Connection for multiple + /// calls, without having a pooling ConnectionFactory underneath. This may span + /// any number of transactions, even concurrently executing transactions. /// /// /// Note that Spring's message listener containers support the use of @@ -84,6 +88,7 @@ namespace Spring.Messaging.Nms.Connections /// private object connectionMonitor = new object(); + #endregion #region Constructors @@ -180,7 +185,7 @@ namespace Spring.Messaging.Nms.Connections /// /// /// - /// true if [reconnect on exception]; otherwise, false. + /// true attempt to reconnect on exception during next access; otherwise, false. /// public bool ReconnectOnException { @@ -275,16 +280,10 @@ namespace Spring.Messaging.Nms.Connections IExceptionListener listenerToUse = ExceptionListener; if (ReconnectOnException) { - InternalChainedExceptionListener chained = new InternalChainedExceptionListener(this, listenerToUse); - con.ExceptionListener += chained.OnException; - } - else - { - if (ExceptionListener != null) - { - con.ExceptionListener += ExceptionListener.OnException; - } + //add reconnect exception handler first. + con.ExceptionListener += new ExceptionListener(this.OnException); } + con.ExceptionListener += new ExceptionListener(listenerToUse.OnException); } } @@ -389,25 +388,6 @@ namespace Spring.Messaging.Nms.Connections } } - internal class InternalChainedExceptionListener : ChainedExceptionListener, IExceptionListener - { - private IExceptionListener userListener; - public InternalChainedExceptionListener(IExceptionListener internalListener, IExceptionListener userListener) - { - AddListener(internalListener); - if (userListener != null) - { - AddListener(userListener); - this.userListener = userListener; - } - } - - public IExceptionListener UserListener - { - get { return userListener; } - } - } - internal class CloseSupressingConnection : IConnection { private IConnection target; @@ -432,7 +412,8 @@ namespace Spring.Messaging.Nms.Connections else { throw new ArgumentException( - "Setting of 'ClientID' property not supported on wrapper for shared Connection." + + "Setting of 'ClientID' property not supported on wrapper for shared Connection since" + + "this is a shared connection that may serve any number of clients concurrently." + "Set the 'ClientId' property on the SingleConnectionFactory instead."); } @@ -446,7 +427,7 @@ namespace Spring.Messaging.Nms.Connections public void Stop() { - //don't pass the call to the target. + //don't pass the call to the target as it would stop receiving for all clients sharing this connection. } public ISession CreateSession() @@ -473,7 +454,10 @@ namespace Spring.Messaging.Nms.Connections { target.ExceptionListener += value; } - remove { target.ExceptionListener -= value; } + remove + { + target.ExceptionListener -= value; + } } 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 fef4e4f2..ae525fc2 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractListenerContainer.cs @@ -435,24 +435,6 @@ namespace Spring.Messaging.Nms.Listener sharedConnection.Start(); } } - /* - bool running = IsRunning; - lock (this.sharedConnectionMonitor) - { - MessagingUtils.CloseConnection(this.sharedConnection, running); - - IConnection con = CreateConnection(); - try - { - PrepareSharedConnection(con); - } - catch (Exception) - { - MessagingUtils.CloseConnection(con); - throw; - } - this.sharedConnection = con; - }*/ } /// @@ -471,7 +453,7 @@ namespace Spring.Messaging.Nms.Listener { PrepareSharedConnection(con); return con; - } catch (NMSException) + } catch (Exception) { NmsUtils.CloseConnection(con); throw; diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs index 065d433c..c816fee0 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/AbstractMessageListenerContainer.cs @@ -19,6 +19,8 @@ #endregion using System; +using System.Collections; +using System.IO; using Common.Logging; using Spring.Messaging.Nms.Core; using Spring.Messaging.Nms.Support; @@ -261,7 +263,6 @@ namespace Spring.Messaging.Nms.Listener set { acceptMessagesWhileStopping = value; } } - #endregion @@ -538,7 +539,7 @@ namespace Spring.Messaging.Nms.Listener } if (ex is NMSException) { - InvokeExceptionListener((NMSException)ex); + InvokeExceptionListener(ex); } if (Active) { diff --git a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.cs new file mode 100644 index 00000000..e32e7e29 --- /dev/null +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/RecoveryTimeExceededException.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 +{ + /// + /// Exception thrown when the maximum connection recovery time has been exceeded. + /// + /// Mark Pollack + public class RecoveryTimeExceededException : NMSException + { + + /// + /// Initializes a new instance of the class, with the specified message + /// + /// The message. + public RecoveryTimeExceededException(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 RecoveryTimeExceededException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} \ No newline at end of file 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 23629da0..9a368a32 100644 --- a/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs +++ b/src/Spring/Spring.Messaging.Nms/Messaging/Nms/Listener/SimpleMessageListenerContainer.cs @@ -19,6 +19,7 @@ #endregion using System; +using System.Threading; using Common.Logging; using Spring.Collections; using Spring.Messaging.Nms.Core; @@ -44,6 +45,16 @@ namespace Spring.Messaging.Nms.Listener #region fields + /// + /// The default recovery time interval between connection reconnection attempts + /// + public static TimeSpan DEFAULT_RECOVERY_INTERVAL = new TimeSpan(0,0,0,5,0); + + /// + /// The total time connection recovery will be attempted. + /// + public static TimeSpan DEFAULT_MAX_RECOVERY_TIME = new TimeSpan(0, 0, 10, 0, 0); + private bool pubSubNoLocal = false; private int concurrentConsumers = 1; @@ -54,6 +65,11 @@ namespace Spring.Messaging.Nms.Listener private object consumersMonitor = new object(); + private TimeSpan recoveryInterval = DEFAULT_RECOVERY_INTERVAL; + + private TimeSpan maxRecoveryTime = DEFAULT_MAX_RECOVERY_TIME; + + #endregion #region Properties @@ -92,6 +108,26 @@ namespace Spring.Messaging.Nms.Listener } } + + /// + /// Sets the time interval between connection recovery attempts. The default is 5 seconds. + /// + /// The recovery interval. + public TimeSpan RecoveryInterval + { + set { recoveryInterval = value; } + } + + + /// + /// Sets the max recovery time to try reconnection attempts. The default is 10 minutes. + /// + /// The max recovery time. + public TimeSpan MaxRecoveryTime + { + set { maxRecoveryTime = value; } + } + /// /// Always use a shared NMS connection /// @@ -143,7 +179,7 @@ namespace Spring.Messaging.Nms.Listener protected override void PrepareSharedConnection(IConnection connection) { base.PrepareSharedConnection(connection); - connection.ExceptionListener += OnException; + connection.ExceptionListener += new ExceptionListener(OnException); } @@ -156,7 +192,7 @@ namespace Spring.Messaging.Nms.Listener public void OnException(Exception exception) { // First invoke the user-specific ExceptionListener, if any. - InvokeExceptionListener(exception); + //InvokeExceptionListener(exception); // now try to recover the shared Connection and all consumers... if (logger.IsInfoEnabled) { @@ -164,21 +200,74 @@ namespace Spring.Messaging.Nms.Listener } try { - lock(consumersMonitor) + lock (consumersMonitor) { sessions = null; consumers = null; } - RefreshSharedConnection(); + RefreshConnectionUntilSuccessful(); InitializeConsumers(); logger.Info("Successfully refreshed NMS Connection"); - } catch (NMSException recoverEx) + } catch (RecoveryTimeExceededException) + { + throw; + } catch (Exception recoverEx) { logger.Debug("Failed to recover NMS Connection", recoverEx); - logger.Error("Encountered non-recoverable NMSException", exception); + logger.Error("Encountered non-recoverable Exception", exception); + throw; } } + /// + /// Refresh the underlying Connection, not returning before an attempt has been + /// successful. Called in case of a shared Connection as well as without shared + /// Connection, so either needs to operate on the shared Connection or on a + /// temporary Connection that just gets established for validation purposes. + /// + /// + /// The default implementation retries until it successfully established a + /// Connection, for as long as this message listener container is active. + /// Applies the specified recovery interval between retries. + /// + protected virtual void RefreshConnectionUntilSuccessful() + { + TimeSpan totalTryTime = new TimeSpan(); + while (IsRunning) + { + try + { + RefreshSharedConnection(); + break; + } catch (Exception ex) + { + if (logger.IsInfoEnabled) + { + logger.Info("Could not refresh Connection - retrying in " + recoveryInterval, ex); + } + } + + if (totalTryTime > maxRecoveryTime) + { + logger.Info("Could not refresh Connection after " + totalTryTime + ". Stopping reconnection attempts."); + throw new RecoveryTimeExceededException("Could not recover after " + totalTryTime); + } + + DateTime startTime = DateTime.Now; + SleepInBetweenRecoveryAttempts(); + TimeSpan sleepTimeSpan = DateTime.Now - startTime; + totalTryTime += sleepTimeSpan; + } + } + + /// + /// The amount of time to sleep in between recovery attempts. + /// + protected virtual void SleepInBetweenRecoveryAttempts() + { + Thread.Sleep(recoveryInterval); + } + /// /// Initialize the Sessions and MessageConsumers for this container. /// diff --git a/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj b/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj index 6898cd1e..72d29e27 100644 --- a/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj +++ b/src/Spring/Spring.Messaging.Nms/Spring.Messaging.Nms.2005.csproj @@ -79,6 +79,7 @@ + diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs new file mode 100644 index 00000000..68f621a2 --- /dev/null +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Core/SimpleMessageListenerContainerTests.cs @@ -0,0 +1,159 @@ +#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 + +#region Imports + +using System; +using Apache.NMS; +using NUnit.Framework; +using Rhino.Mocks; +using Spring.Messaging.Nms.Listener; + +#endregion + +namespace Spring.Messaging.Nms.Core +{ + /// + /// This class contains tests for + /// + /// Mark Pollack + /// $Id:$ + [TestFixture] + public class SimpleMessageListenerContainerTests + { + private static string DESTINATION_NAME = "foo"; + + private static StubQueue QUEUE_DESTINATION = new StubQueue(); + + private static string EXCEPTION_MESSAGE = "This.Is.It"; + + private SimpleMessageListenerContainer container; + + private MockRepository mocks; + + + [SetUp] + public void Setup() + { + mocks = new MockRepository(); + container = new SimpleMessageListenerContainer(); + } + + + + [Test] + public void RegisteredExceptionListenerIsInvokedOnException() + { + SimpleMessageConsumer messageConsumer = new SimpleMessageConsumer(); + + ISession session = (ISession) mocks.CreateMock(typeof (ISession)); + Expect.Call(session.GetQueue(DESTINATION_NAME)).Return(QUEUE_DESTINATION); + Expect.Call(session.CreateConsumer(QUEUE_DESTINATION, null)).Return(messageConsumer); + // an exception is thrown, so the rollback logic is being applied here... + Expect.Call(session.Transacted).Return(false); + + IConnection connection = (IConnection)mocks.CreateMock(typeof(IConnection)); + connection.ExceptionListener += container.OnException; + Expect.Call(connection.CreateSession(container.SessionAcknowledgeMode)).Return(session); + connection.Start(); + + IConnectionFactory connectionFactory = (IConnectionFactory) mocks.CreateMock(typeof (IConnectionFactory)); + Expect.Call(connectionFactory.CreateConnection()).Return(connection); + + NMSException theException = new NMSException(EXCEPTION_MESSAGE); + + IExceptionListener exceptionListener = (IExceptionListener) mocks.CreateMock(typeof (IExceptionListener)); + exceptionListener.OnException(theException); + + IMessage message = (IMessage) mocks.CreateMock(typeof (IMessage)); + + mocks.ReplayAll(); + + + container.ConnectionFactory = connectionFactory; + container.DestinationName = DESTINATION_NAME; + container.MessageListener = new BadSessionAwareMessageListener(theException); + container.ExceptionListener = exceptionListener; + container.AfterPropertiesSet(); + + // manually trigger an Exception with the above bad MessageListener... + messageConsumer.SendMessage(message); + + + + mocks.VerifyAll(); + + + + + + } + } + + internal class BadSessionAwareMessageListener : ISessionAwareMessageListener + { + private NMSException exception; + public BadSessionAwareMessageListener(NMSException exception) + { + this.exception = exception; + } + + public void OnMessage(IMessage message, ISession session) + { + throw exception; + } + } + + internal class SimpleMessageConsumer : IMessageConsumer + { + public event MessageListener Listener; + + public void SendMessage(IMessage message) + { + Listener(message); + } + public IMessage Receive() + { + throw new NotImplementedException(); + } + + public IMessage Receive(TimeSpan timeout) + { + throw new NotImplementedException(); + } + + public IMessage ReceiveNoWait() + { + throw new NotImplementedException(); + } + + public void Close() + { + throw new NotImplementedException(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } + + + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs index 935af7e1..f561f522 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/Integration/SimpleMessageListenerContainerTests.cs @@ -32,7 +32,7 @@ using Spring.Testing.NUnit; namespace Spring.Messaging.Nms.Integration { /// - /// This class contains tests for + /// This class contains integration tests for the SimpleMessageListenerContainer /// /// Mark Pollack /// $Id:$ diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs new file mode 100644 index 00000000..b4d38365 --- /dev/null +++ b/test/Spring/Spring.Messaging.Nms.Tests/Messaging/Nms/StubQueue.cs @@ -0,0 +1,64 @@ +#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 Apache.NMS; + +namespace Spring.Messaging.Nms +{ + /// + /// + /// + /// + /// + /// + /// Mark Pollack + public class StubQueue : IQueue + { + public static string DEFAULT_QUEUE_NAME = "banjo"; + + + private string queueName = DEFAULT_QUEUE_NAME; + + public string QueueName + { + get { return queueName; } + } + + public DestinationType DestinationType + { + get { return DestinationType.Queue; } + } + + public bool IsTopic + { + get { return false; } + } + + public bool IsQueue + { + get { return true; } + } + + public bool IsTemporary + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2005.csproj b/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2005.csproj index 7a06918b..fcecb4bb 100644 --- a/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2005.csproj +++ b/test/Spring/Spring.Messaging.Nms.Tests/Spring.Messaging.Nms.Tests.2005.csproj @@ -98,10 +98,12 @@ + +