Improving the dynamic factory loading routine.
Fixes [AMQNET-333]. (See https://issues.apache.org/jira/browse/AMQNET-333)

diff --git a/src/main/csharp/CommonConnectionFactory.cs b/src/main/csharp/CommonConnectionFactory.cs
index c7adbf8..c19537d 100644
--- a/src/main/csharp/CommonConnectionFactory.cs
+++ b/src/main/csharp/CommonConnectionFactory.cs
@@ -17,6 +17,8 @@
 

 using System;

 using System.Reflection;

+using System.Collections;

+using System.IO;

 

 namespace Apache.NMS.ZMQ

 {

@@ -34,50 +36,14 @@
 		// 64-bit runtimes' ItrPtr size is 8.

 		static private bool is32bit = (IntPtr.Size == 4);

 

+		private static Assembly factoryAssembly = null;

 		private static Type factoryType = null;

 		private IConnectionFactory connFactory = null;

+		private object connectionFactoryLock = new object();

 

 		private const string DEFAULT_BROKER_URL = "tcp://localhost:5556";

 		private const string ENV_BROKER_URL = "ZMQ_BROKER_URL";

 

-		/// <summary>

-		/// Static class constructor that is executed only once before any normal object constructors.

-		/// This is the type constructor.

-		/// </summary>

-		static ConnectionFactory()

-		{

-			// Load the assembly and get the type.

-			string assemblyFileName = (is32bit ? "Apache.NMS.ZMQ32.dll" : "Apache.NMS.ZMQ64.dll");

-			Assembly assembly;

-

-			try

-			{

-				assembly = Assembly.Load(assemblyFileName);

-				if(null != assembly)

-				{

-					Tracer.DebugFormat("Succesfully loaded provider: {0}", assemblyFileName);

-					factoryType = assembly.GetType("Apache.NMS.ZMQ.ConnectionFactory", true, true);

-				}

-			}

-			catch(Exception ex)

-			{

-				Tracer.ErrorFormat("Exception loading assembly {0} failed: {1}", assemblyFileName, ex.Message);

-				factoryType = null;

-			}

-		}

-

-		private static string GetDefaultBrokerUrl()

-		{

-			string brokerUrl = Environment.GetEnvironmentVariable(ENV_BROKER_URL);

-

-			if(string.IsNullOrEmpty(brokerUrl))

-			{

-				brokerUrl = DEFAULT_BROKER_URL;

-			}

-

-			return brokerUrl;

-		}

-

 		public ConnectionFactory()

 			: this(GetDefaultBrokerUrl())

 		{

@@ -100,12 +66,100 @@
 

 		public ConnectionFactory(Uri brokerUri, string clientID)

 		{

-			if(null == factoryType)

+			LoadConnectionFactory();

+			connFactory = (IConnectionFactory) Activator.CreateInstance(factoryType, new object[] { brokerUri, clientID });

+		}

+

+		/// <summary>

+		/// Static class constructor that is executed only once before any normal object constructors.

+		/// This is the type constructor.

+		/// </summary>

+		private void LoadConnectionFactory()

+		{

+			lock(connectionFactoryLock)

 			{

-				throw new ApplicationException("Could not load the ZMQ connection factory assembly.");

+				if(null == factoryType)

+				{

+					// Load the assembly and get the type.

+					string assemblyFileName = (is32bit ? "Apache.NMS.ZMQ32.dll" : "Apache.NMS.ZMQ64.dll");

+					string[] searchPaths = GetAssemblySearchPaths();

+

+					foreach(string path in searchPaths)

+					{

+						string fullFileName = Path.Combine(path, assemblyFileName);

+

+						try

+						{

+							factoryAssembly = Assembly.Load(fullFileName);

+							if(null != factoryAssembly)

+							{

+								Tracer.DebugFormat("Succesfully loaded provider: {0}", fullFileName);

+								factoryType = factoryAssembly.GetType("Apache.NMS.ZMQ.ConnectionFactory", true, true);

+								if(null != factoryType)

+								{

+									break;

+								}

+							}

+						}

+						catch(Exception ex)

+						{

+							Tracer.DebugFormat("Exception loading assembly {0} failed: {1}", fullFileName, ex.Message);

+							factoryType = null;

+						}

+					}

+

+					if(null == factoryType)

+					{

+						Tracer.ErrorFormat("Failed to load assembly {0}", assemblyFileName);

+						throw new ApplicationException(string.Format("Could not load the ZMQ connection factory assembly {0}.", assemblyFileName));

+					}

+				}

+			}

+		}

+

+		/// <summary>

+		/// Get the paths to search for the assembly file.

+		/// </summary>

+		/// <returns></returns>

+		private static string[] GetAssemblySearchPaths()

+		{

+			ArrayList pathList = new ArrayList();

+

+			// Check the current folder first.

+			pathList.Add("");

+

+			// Check the folder the assembly is located in.

+			AppDomain currentDomain = AppDomain.CurrentDomain;

+

+			pathList.Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));

+			if(null != currentDomain.BaseDirectory)

+			{

+				pathList.Add(currentDomain.BaseDirectory);

 			}

 

-			connFactory = (IConnectionFactory) Activator.CreateInstance(factoryType, new object[] { brokerUri, clientID });

+			if(null != currentDomain.RelativeSearchPath)

+			{

+				pathList.Add(currentDomain.RelativeSearchPath);

+			}

+

+			return (string[]) pathList.ToArray(typeof(string));

+		}

+

+		/// <summary>

+		/// Get the default connection Uri if none is specified.

+		/// The environment variable is checked first.

+		/// </summary>

+		/// <returns></returns>

+		private static string GetDefaultBrokerUrl()

+		{

+			string brokerUrl = Environment.GetEnvironmentVariable(ENV_BROKER_URL);

+

+			if(string.IsNullOrEmpty(brokerUrl))

+			{

+				brokerUrl = DEFAULT_BROKER_URL;

+			}

+

+			return brokerUrl;

 		}

 

 		#region IConnectionFactory Members

diff --git a/src/test/csharp/ZMQTest.cs b/src/test/csharp/ZMQTest.cs
index 189e248..957850d 100644
--- a/src/test/csharp/ZMQTest.cs
+++ b/src/test/csharp/ZMQTest.cs
@@ -19,6 +19,7 @@
 using System.Messaging;

 using NUnit.Framework;

 using System.Threading;

+using System.IO;

 

 namespace Apache.NMS.ZMQ

 {

@@ -48,23 +49,17 @@
 			////////////////////////////

 			// Dependencies check

 			////////////////////////////

-			string TmpPath;

-			string TmpFilename;

-			//TmpPath = System.Reflection.Assembly.GetExecutingAssembly().Location;

-			TmpPath = System.Environment.CurrentDirectory;

-			if(!TmpPath.EndsWith("\\"))

-			{

-				TmpPath += "\\";

-			}

+			string libFolder = System.Environment.CurrentDirectory;

+			string libFileName;

 

-			TmpFilename = TmpPath + "libzmq.dll";

-			Assert.IsTrue(System.IO.File.Exists(TmpFilename), "Missing zmq library file: {0}", TmpFilename);

-			TmpFilename = TmpPath + "clrzmq.dll";

-			Assert.IsTrue(System.IO.File.Exists(TmpFilename), "Missing zmq wrapper file: {0}", TmpFilename);

-			TmpFilename = TmpPath + "Apache.NMS.dll";

-			Assert.IsTrue(System.IO.File.Exists(TmpFilename), "Missing Apache.NMS library file: {0}", TmpFilename);

-			TmpFilename = TmpPath + "Apache.NMS.ZMQ.dll";

-			Assert.IsTrue(System.IO.File.Exists(TmpFilename), "Missing Apache.NMS.ZMQ library file: {0}", TmpFilename);

+			libFileName = Path.Combine(libFolder, "libzmq.dll");

+			Assert.IsTrue(File.Exists(libFileName), "Missing zmq library file: {0}", libFileName);

+			libFileName = Path.Combine(libFolder, "clrzmq.dll");

+			Assert.IsTrue(File.Exists(libFileName), "Missing zmq wrapper file: {0}", libFileName);

+			libFileName = Path.Combine(libFolder, "Apache.NMS.dll");

+			Assert.IsTrue(File.Exists(libFileName), "Missing Apache.NMS library file: {0}", libFileName);

+			libFileName = Path.Combine(libFolder, "Apache.NMS.ZMQ.dll");

+			Assert.IsTrue(File.Exists(libFileName), "Missing Apache.NMS.ZMQ library file: {0}", libFileName);

 

 			////////////////////////////

 			// Factory check