diff --git a/src/Spring/Spring.Core/Expressions/MethodNode.cs b/src/Spring/Spring.Core/Expressions/MethodNode.cs
index f308ed42..cdf2460e 100644
--- a/src/Spring/Spring.Core/Expressions/MethodNode.cs
+++ b/src/Spring/Spring.Core/Expressions/MethodNode.cs
@@ -1,19 +1,19 @@
#region License
-/*
- * Copyright © 2002-2005 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.
+/*
+ * Copyright © 2002-2005 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
@@ -95,6 +95,8 @@ namespace Spring.Expressions
{
string methodName = this.getText();
object[] argValues = ResolveArguments(evalContext);
+ ICollectionProcessor localCollectionProcessor = null;
+ IMethodCallProcessor methodCallProcessor = null;
// resolve method, if necessary
lock (this)
@@ -102,35 +104,24 @@ namespace Spring.Expressions
// check if it is a collection and the methodname denotes a collection processor
if ((context == null || context is ICollection))
{
- ICollectionProcessor localCollectionProcessor;
// predefined collection processor?
- localCollectionProcessor = (ICollectionProcessor) collectionProcessorMap[methodName];
+ localCollectionProcessor = (ICollectionProcessor)collectionProcessorMap[methodName];
// user-defined collection processor?
if (localCollectionProcessor == null && evalContext.Variables != null)
{
localCollectionProcessor = evalContext.Variables[methodName] as ICollectionProcessor;
}
-
- if (localCollectionProcessor != null)
- {
- return localCollectionProcessor.Process((ICollection) context, argValues);
- }
}
// try extension methods
- IMethodCallProcessor methodCallProcessor = (IMethodCallProcessor)extensionMethodProcessorMap[methodName];
+ methodCallProcessor = (IMethodCallProcessor)extensionMethodProcessorMap[methodName];
{
// user-defined extension method processor?
if (methodCallProcessor == null && evalContext.Variables != null)
{
methodCallProcessor = evalContext.Variables[methodName] as IMethodCallProcessor;
}
-
- if (methodCallProcessor != null)
- {
- return methodCallProcessor.Process(context, argValues);
- }
}
// try instance method
@@ -148,18 +139,28 @@ namespace Spring.Expressions
Initialize(methodName, argValues, context);
initialized = true;
}
-
- if (cachedInstanceMethod != null)
- {
- object[] paramValues = (cachedIsParamArray)
- ? ReflectionUtils.PackageParamArray(argValues, argumentCount, paramArrayType)
- : argValues;
- return cachedInstanceMethod.Invoke(context, paramValues);
- }
}
}
-
- throw new ArgumentException(string.Format("Method '{0}' with the specified number and types of arguments does not exist.", methodName));
+
+ if (localCollectionProcessor != null)
+ {
+ return localCollectionProcessor.Process((ICollection)context, argValues);
+ }
+ else if (methodCallProcessor != null)
+ {
+ return methodCallProcessor.Process(context, argValues);
+ }
+ else if (cachedInstanceMethod != null)
+ {
+ object[] paramValues = (cachedIsParamArray)
+ ? ReflectionUtils.PackageParamArray(argValues, argumentCount, paramArrayType)
+ : argValues;
+ return cachedInstanceMethod.Invoke(context, paramValues);
+ }
+ else
+ {
+ throw new ArgumentException(string.Format("Method '{0}' with the specified number and types of arguments does not exist.", methodName));
+ }
}
private int CalculateMethodHash(Type contextType, object[] argValues)
@@ -268,21 +269,21 @@ namespace Spring.Expressions
}
// used to calculate signature hash while caring for arg positions
- private static readonly int[] s_primes =
- {
- 17, 19, 23, 29
- , 31, 37, 41, 43, 47, 53, 59, 61, 67, 71
- , 73, 79, 83, 89, 97, 101, 103, 107, 109, 113
- , 127, 131, 137, 139, 149, 151, 157, 163, 167, 173
- , 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
- , 233, 239, 241, 251, 257, 263, 269, 271, 277, 281
- , 283, 293, 307, 311, 313, 317, 331, 337, 347, 349
- , 353, 359, 367, 373, 379, 383, 389, 397, 401, 409
- , 419, 421, 431, 433, 439, 443, 449, 457, 461, 463
- , 467, 479, 487, 491, 499, 503, 509, 521, 523, 541
- , 547, 557, 563, 569, 571, 577, 587, 593, 599, 601
- , 607, 613, 617, 619, 631, 641, 643, 647, 653, 659
- , 661, 673, 677, 683, 691, 701, 709, 719, 727, 733
+ private static readonly int[] s_primes =
+ {
+ 17, 19, 23, 29
+ , 31, 37, 41, 43, 47, 53, 59, 61, 67, 71
+ , 73, 79, 83, 89, 97, 101, 103, 107, 109, 113
+ , 127, 131, 137, 139, 149, 151, 157, 163, 167, 173
+ , 179, 181, 191, 193, 197, 199, 211, 223, 227, 229
+ , 233, 239, 241, 251, 257, 263, 269, 271, 277, 281
+ , 283, 293, 307, 311, 313, 317, 331, 337, 347, 349
+ , 353, 359, 367, 373, 379, 383, 389, 397, 401, 409
+ , 419, 421, 431, 433, 439, 443, 449, 457, 461, 463
+ , 467, 479, 487, 491, 499, 503, 509, 521, 523, 541
+ , 547, 557, 563, 569, 571, 577, 587, 593, 599, 601
+ , 607, 613, 617, 619, 631, 641, 643, 647, 653, 659
+ , 661, 673, 677, 683, 691, 701, 709, 719, 727, 733
};
}
}
diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs
index ba93916c..1770980f 100644
--- a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs
+++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/DistributedTxMessageListenerContainerTests.cs
@@ -81,11 +81,11 @@ namespace Spring.Messaging.Listener
q.ConvertAndSend("Goodbye World 1");
Assert.AreEqual(0, listener.MessageCount, "PRECONDITION FAILURE: Unable to send the message!");
+
distributedTxMessageListenerContainer.Start();
Thread.Sleep(waitInMillis);
-
distributedTxMessageListenerContainer.Stop();
distributedTxMessageListenerContainer.Shutdown();
Thread.Sleep(2500);
@@ -105,6 +105,8 @@ namespace Spring.Messaging.Listener
//must match the retry count in the object registration for test to pass!
const int EXCEPTION_QUEUE_RETRY_COUNT = 2;
+ int expectedMessageCount = MESSAGE_COUNT + (MESSAGE_COUNT * EXCEPTION_QUEUE_RETRY_COUNT);
+
MessageQueueTemplate q = applicationContext["queueTemplate"] as MessageQueueTemplate;
Assert.IsNotNull(q);
@@ -115,13 +117,22 @@ namespace Spring.Messaging.Listener
Assert.AreEqual(0, listener.MessageCount);
+ System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
+ timer.Start();
+
distributedTxMessageListenerContainer.Start();
- //this test needs to wait somewhat longer than the others in order to consistently pass so
- //artificially inflate the waiting period before attempting subsequent asserts:
- Thread.Sleep((int)(waitInMillis * 1.5));
+ while (listener.MessageCount < expectedMessageCount)
+ {
+ if (timer.ElapsedMilliseconds > 60000)
+ Assert.Fail("Did not receive expected number of messages within the permitted time limit.");
+ }
- Assert.AreEqual(MESSAGE_COUNT + (MESSAGE_COUNT * EXCEPTION_QUEUE_RETRY_COUNT), listener.MessageCount);
+ timer.Stop();
+
+ System.Diagnostics.Debug.WriteLine("elapsed time = " + timer.ElapsedMilliseconds);
+
+ Assert.AreEqual(expectedMessageCount, listener.MessageCount);
distributedTxMessageListenerContainer.Stop();
distributedTxMessageListenerContainer.Shutdown();
diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs
new file mode 100644
index 00000000..6c79e12c
--- /dev/null
+++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.cs
@@ -0,0 +1,120 @@
+#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.Threading;
+using NUnit.Framework;
+using Spring.Messaging.Core;
+using Spring.Testing.NUnit;
+using System.Diagnostics;
+using System;
+
+#endregion
+
+namespace Spring.Messaging.Listener
+{
+ ///
+ /// This class contains tests for
+ ///
+ /// Mark Pollack
+ /// $Id:$
+ [TestFixture]
+ public class MultiThreadedNonTransactionalMessageListenerContainerTests : AbstractDependencyInjectionSpringContextTests
+ {
+
+ private NonTransactionalMessageListenerContainer container;
+ private WaitingHandler listener;
+ private SimpleExceptionHandler exceptionHandler;
+
+ [SetUp]
+ public override void SetUp()
+ {
+ MessageQueueUtils.RecreateMessageQueue(@".\Private$\testqueue", false);
+ MessageQueueUtils.RecreateMessageQueue(@".\Private$\testresponsequeue", false);
+ base.SetUp();
+ }
+
+ public SimpleExceptionHandler ExceptionHandler
+ {
+ set { exceptionHandler = value; }
+ }
+
+ public NonTransactionalMessageListenerContainer Container
+ {
+ get { return container; }
+ set { container = value; }
+ }
+
+ public WaitingHandler Listener
+ {
+ get { return listener; }
+ set { listener = value; }
+ }
+
+
+ [Test]
+ public void Test()
+ {
+ System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
+
+ MessageQueueTemplate q = applicationContext["testQueueTemplate"] as MessageQueueTemplate;
+ Assert.IsNotNull(q);
+
+ q.ConvertAndSend("Hello World 1");
+ q.ConvertAndSend("Hello World 2");
+ q.ConvertAndSend("Hello World 3");
+ q.ConvertAndSend("Hello World 4");
+ q.ConvertAndSend("Hello World 5");
+
+ //Reset the state so that running all tests together will succeed.
+ exceptionHandler.MessageCount = 0;
+
+ Assert.AreEqual(0, listener.MessageCount);
+
+ timer.Start();
+
+ container.Start();
+
+ while (listener.MessageCount < 5)
+ {
+ //provide an exit if the test is completely over-length
+ if (timer.ElapsedMilliseconds > 120000)
+ Assert.Fail("Did not receive expected number of messages with the expected time-limit!");
+ }
+
+ timer.Stop();
+
+ container.Stop();
+ container.Shutdown();
+
+ Debug.WriteLine(String.Format("Elapsed Milliseconds: {0}", timer.ElapsedMilliseconds));
+
+ Assert.Less(timer.ElapsedMilliseconds, 50000);
+ Assert.AreEqual(5, listener.MessageCount);
+ Assert.AreEqual(0, exceptionHandler.MessageCount);
+ }
+
+ protected override string[] ConfigLocations
+ {
+ get { return new string[] { "assembly://Spring.Messaging.Tests/Spring.Messaging.Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml" }; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml
new file mode 100644
index 00000000..5845daa5
--- /dev/null
+++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/MultiThreadedNonTransactionalMessageListenerContainerTests.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs
new file mode 100644
index 00000000..8f1ea80c
--- /dev/null
+++ b/test/Spring/Spring.Messaging.Tests/Messaging/Listener/WaitingHandler.cs
@@ -0,0 +1,49 @@
+
+
+using System;
+using Common.Logging;
+using System.Threading;
+
+namespace Spring.Messaging.Listener
+{
+ public class WaitingHandler
+ {
+ #region Logging
+
+ private static readonly ILog LOG = LogManager.GetLogger(typeof(WaitingHandler));
+
+ #endregion
+
+ private int messageCount;
+
+ private string stateVariable;
+
+ public WaitingHandler()
+ {
+ this.stateVariable = "hello";
+ }
+ public WaitingHandler(string stateVariable)
+ {
+ this.stateVariable = stateVariable;
+ }
+
+
+ public int MessageCount
+ {
+ get { return messageCount; }
+ set { messageCount = value; }
+ }
+
+ public string HandleMessage(string msgTxt)
+ {
+ LOG.Debug(String.Format("Received text = [{0}]", msgTxt));
+ LOG.Debug("constructor set state string = " + stateVariable);
+
+ Thread.Sleep(10000);
+
+ messageCount++;
+ LOG.Debug("Message listener count = " + messageCount);
+ return msgTxt + " - processed!";
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj
index 226e0bd1..8350424c 100644
--- a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj
+++ b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2005.csproj
@@ -75,6 +75,7 @@
+
@@ -87,11 +88,13 @@
+
-
+
+
Code
diff --git a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj
index fc0bcbe0..f451fbca 100644
--- a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj
+++ b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2008.csproj
@@ -76,6 +76,7 @@
+
@@ -88,13 +89,15 @@
+
-
+
+
Code
diff --git a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2010.csproj b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2010.csproj
index e0e3d53e..7a17a1db 100644
--- a/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2010.csproj
+++ b/test/Spring/Spring.Messaging.Tests/Spring.Messaging.Tests.2010.csproj
@@ -56,6 +56,8 @@
+
+
@@ -88,6 +90,9 @@
+
+ Designer
+
Always