You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ha...@apache.org on 2022/03/27 10:34:07 UTC
[activemq-nms-api] 01/01: AMQNET-745 fixed NRE for single file assembly
This is an automated email from the ASF dual-hosted git repository.
havret pushed a commit to branch feature/AMQNET-745
in repository https://gitbox.apache.org/repos/asf/activemq-nms-api.git
commit 104b5690e590f1bbaca49dc2f01fc7fa68c1e269
Author: Yulia Fatkullina <i7...@gmail.com>
AuthorDate: Thu Dec 9 13:17:12 2021 +0300
AMQNET-745 fixed NRE for single file assembly
# Conflicts:
# src/nms-api/NMSConnectionFactory.cs
---
src/nms-api/NMSConnectionFactory.cs | 878 ++++++++++++++++++------------------
1 file changed, 441 insertions(+), 437 deletions(-)
diff --git a/src/nms-api/NMSConnectionFactory.cs b/src/nms-api/NMSConnectionFactory.cs
index b09ee4f..89bdef1 100644
--- a/src/nms-api/NMSConnectionFactory.cs
+++ b/src/nms-api/NMSConnectionFactory.cs
@@ -1,440 +1,444 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Xml;
-
-using Apache.NMS.Util;
-
-namespace Apache.NMS
-{
- /// <summary>
- /// Provider implementation mapping class.
- /// </summary>
- public class ProviderFactoryInfo
- {
- public string assemblyFileName;
- public string factoryClassName;
-
- public ProviderFactoryInfo(string aFileName, string fClassName)
- {
- assemblyFileName = aFileName;
- factoryClassName = fClassName;
- }
- }
-
- /// <summary>
- /// Implementation of a factory for <see cref="IConnection" /> instances.
- /// </summary>
- public class NMSConnectionFactory : IConnectionFactory
- {
- protected readonly IConnectionFactory factory;
- protected static readonly Dictionary<string, ProviderFactoryInfo> schemaProviderFactoryMap;
-
- /// <summary>
- /// Static class constructor
- /// </summary>
- static NMSConnectionFactory()
- {
- schemaProviderFactoryMap = new Dictionary<string, ProviderFactoryInfo>();
- schemaProviderFactoryMap["activemq"] = new ProviderFactoryInfo("Apache.NMS.ActiveMQ", "Apache.NMS.ActiveMQ.ConnectionFactory");
- schemaProviderFactoryMap["activemqnettx"] = new ProviderFactoryInfo("Apache.NMS.ActiveMQ", "Apache.NMS.ActiveMQ.NetTxConnectionFactory");
- schemaProviderFactoryMap["tcp"] = new ProviderFactoryInfo("Apache.NMS.ActiveMQ", "Apache.NMS.ActiveMQ.ConnectionFactory");
- schemaProviderFactoryMap["ems"] = new ProviderFactoryInfo("Apache.NMS.EMS", "Apache.NMS.EMS.ConnectionFactory");
- schemaProviderFactoryMap["mqtt"] = new ProviderFactoryInfo("Apache.NMS.MQTT", "Apache.NMS.MQTT.ConnectionFactory");
- schemaProviderFactoryMap["msmq"] = new ProviderFactoryInfo("Apache.NMS.MSMQ", "Apache.NMS.MSMQ.ConnectionFactory");
- schemaProviderFactoryMap["stomp"] = new ProviderFactoryInfo("Apache.NMS.Stomp", "Apache.NMS.Stomp.ConnectionFactory");
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+
+using Apache.NMS.Util;
+
+namespace Apache.NMS
+{
+ /// <summary>
+ /// Provider implementation mapping class.
+ /// </summary>
+ public class ProviderFactoryInfo
+ {
+ public string assemblyFileName;
+ public string factoryClassName;
+
+ public ProviderFactoryInfo(string aFileName, string fClassName)
+ {
+ assemblyFileName = aFileName;
+ factoryClassName = fClassName;
+ }
+ }
+
+ /// <summary>
+ /// Implementation of a factory for <see cref="IConnection" /> instances.
+ /// </summary>
+ public class NMSConnectionFactory : IConnectionFactory
+ {
+ protected readonly IConnectionFactory factory;
+ protected static readonly Dictionary<string, ProviderFactoryInfo> schemaProviderFactoryMap;
+
+ /// <summary>
+ /// Static class constructor
+ /// </summary>
+ static NMSConnectionFactory()
+ {
+ schemaProviderFactoryMap = new Dictionary<string, ProviderFactoryInfo>();
+ schemaProviderFactoryMap["activemq"] = new ProviderFactoryInfo("Apache.NMS.ActiveMQ", "Apache.NMS.ActiveMQ.ConnectionFactory");
+ schemaProviderFactoryMap["activemqnettx"] = new ProviderFactoryInfo("Apache.NMS.ActiveMQ", "Apache.NMS.ActiveMQ.NetTxConnectionFactory");
+ schemaProviderFactoryMap["tcp"] = new ProviderFactoryInfo("Apache.NMS.ActiveMQ", "Apache.NMS.ActiveMQ.ConnectionFactory");
+ schemaProviderFactoryMap["ems"] = new ProviderFactoryInfo("Apache.NMS.EMS", "Apache.NMS.EMS.ConnectionFactory");
+ schemaProviderFactoryMap["mqtt"] = new ProviderFactoryInfo("Apache.NMS.MQTT", "Apache.NMS.MQTT.ConnectionFactory");
+ schemaProviderFactoryMap["msmq"] = new ProviderFactoryInfo("Apache.NMS.MSMQ", "Apache.NMS.MSMQ.ConnectionFactory");
+ schemaProviderFactoryMap["stomp"] = new ProviderFactoryInfo("Apache.NMS.Stomp", "Apache.NMS.Stomp.ConnectionFactory");
schemaProviderFactoryMap["xms"] = new ProviderFactoryInfo("Apache.NMS.XMS", "Apache.NMS.XMS.ConnectionFactory");
schemaProviderFactoryMap["zmq"] = new ProviderFactoryInfo("Apache.NMS.ZMQ", "Apache.NMS.ZMQ.ConnectionFactory");
schemaProviderFactoryMap["amqp"] = new ProviderFactoryInfo("Apache.NMS.AMQP", "Apache.NMS.AMQP.ConnectionFactory");
- }
-
- /// <summary>
- /// The ConnectionFactory object must define a constructor that takes as a minimum a Uri object.
- /// Any additional parameters are optional, but will typically include a Client ID string.
- /// </summary>
- /// <param name="providerURI">The URI for the ActiveMQ provider.</param>
- /// <param name="constructorParams">Optional parameters to use when creating the ConnectionFactory.</param>
- public NMSConnectionFactory(string providerURI, params object[] constructorParams)
- : this(URISupport.CreateCompatibleUri(providerURI), constructorParams)
- {
- }
-
- /// <summary>
- /// The ConnectionFactory object must define a constructor that takes as a minimum a Uri object.
- /// Any additional parameters are optional, but will typically include a Client ID string.
- /// </summary>
- /// <param name="uriProvider">The URI for the ActiveMQ provider.</param>
- /// <param name="constructorParams">Optional parameters to use when creating the ConnectionFactory.</param>
- public NMSConnectionFactory(Uri uriProvider, params object[] constructorParams)
- {
- this.factory = CreateConnectionFactory(uriProvider, constructorParams);
- }
-
- /// <summary>
- /// Create a connection factory that can create connections for the given scheme in the URI.
- /// </summary>
- /// <param name="uriProvider">The URI for the ActiveMQ provider.</param>
- /// <param name="constructorParams">Optional parameters to use when creating the ConnectionFactory.</param>
- /// <returns>A <see cref="IConnectionFactory" /> implementation that will be used.</returns>
- public static IConnectionFactory CreateConnectionFactory(Uri uriProvider, params object[] constructorParams)
- {
- IConnectionFactory connectionFactory = null;
-
- try
- {
- Type factoryType = GetTypeForScheme(uriProvider.Scheme);
-
- // If an implementation was found, try to instantiate it.
- if(factoryType != null)
- {
-#if NETCF
- // Compact framework does not allow the activator ta pass parameters to a constructor.
- connectionFactory = (IConnectionFactory) Activator.CreateInstance(factoryType);
- connectionFactory.BrokerUri = uriProvider;
-#else
- object[] parameters = MakeParameterArray(uriProvider, constructorParams);
- connectionFactory = (IConnectionFactory) Activator.CreateInstance(factoryType, parameters);
-#endif
- }
-
- if(null == connectionFactory)
- {
- throw new NMSConnectionException("No IConnectionFactory implementation found for connection URI: " + uriProvider);
- }
- }
- catch(NMSConnectionException)
- {
- throw;
- }
- catch(Exception ex)
- {
- throw new NMSConnectionException("Could not create the IConnectionFactory implementation: " + ex.Message, ex);
- }
-
- return connectionFactory;
- }
-
- /// <summary>
- /// Finds the <see cref="System.Type" /> associated with the given scheme.
- /// </summary>
- /// <param name="scheme">The scheme (e.g. <c>tcp</c>, <c>activemq</c> or <c>stomp</c>).</param>
- /// <returns>The <see cref="System.Type" /> of the ConnectionFactory that will be used
- /// to create the connection for the specified <paramref name="scheme" />.</returns>
- private static Type GetTypeForScheme(string scheme)
- {
- string[] paths = GetConfigSearchPaths();
- string assemblyFileName;
- string factoryClassName;
- Type factoryType = null;
-
- Tracer.DebugFormat("Locating provider for scheme: {0}", scheme);
- if(LookupConnectionFactoryInfo(paths, scheme, out assemblyFileName, out factoryClassName))
- {
- Assembly assembly = null;
-
- Tracer.DebugFormat("Attempting to load provider assembly: {0}", assemblyFileName);
- try
- {
- assembly = Assembly.Load(assemblyFileName);
- if(null != assembly)
- {
- Tracer.Debug("Succesfully loaded provider.");
- }
- }
- catch(Exception ex)
- {
- Tracer.ErrorFormat("Exception loading assembly failed: {0}", ex.Message);
- assembly = null;
- }
-
- if(null == assembly)
- {
- foreach(string path in paths)
- {
- string fullpath = Path.Combine(path, assemblyFileName) + ".dll";
-
- Tracer.DebugFormat("Looking for: {0}", fullpath);
- if(File.Exists(fullpath))
- {
- Tracer.Debug("\tAssembly found! Attempting to load...");
- try
- {
- assembly = Assembly.LoadFrom(fullpath);
- }
- catch(Exception ex)
- {
- Tracer.ErrorFormat("Exception loading assembly failed: {0}", ex.Message);
- assembly = null;
- }
-
- if(null != assembly)
- {
- Tracer.Debug("Successfully loaded provider.");
- break;
- }
-
- Tracer.Debug("Failed to load provider. Continuing search...");
- }
- }
- }
-
- if(null != assembly)
- {
-#if NETCF
- factoryType = assembly.GetType(factoryClassName, true);
-#else
- factoryType = assembly.GetType(factoryClassName, true, true);
-#endif
- if(null == factoryType)
- {
- Tracer.Fatal("Failed to load class factory from provider.");
- }
- }
- else
- {
- Tracer.Fatal("Failed to load provider assembly.");
- }
- }
-
- return factoryType;
- }
-
- /// <summary>
- /// Lookup the connection factory assembly filename and class name.
- /// Read an external configuration file that maps scheme to provider implementation.
- /// Load XML config files named: nmsprovider-{scheme}.config
- /// Following is a sample configuration file named nmsprovider-jms.config. Replace
- /// the parenthesis with angle brackets for proper XML formatting.
- ///
- /// (?xml version="1.0" encoding="utf-8" ?)
- /// (configuration)
- /// (provider assembly="MyCompany.NMS.JMSProvider.dll" classFactory="MyCompany.NMS.JMSProvider.ConnectionFactory"/)
- /// (/configuration)
- ///
- /// This configuration file would be loaded and parsed when a connection uri with a scheme of 'jms'
- /// is used for the provider. In this example the connection string might look like:
- /// jms://localhost:7222
- ///
- /// </summary>
- /// <param name="paths">Folder paths to look in.</param>
- /// <param name="scheme">The scheme.</param>
- /// <param name="assemblyFileName">Name of the assembly file.</param>
- /// <param name="factoryClassName">Name of the factory class.</param>
- /// <returns><c>true</c> if the configuration file for the specified <paramref name="scheme" /> could
- /// be found; otherwise, <c>false</c>.</returns>
- private static bool LookupConnectionFactoryInfo(string[] paths, string scheme, out string assemblyFileName, out string factoryClassName)
- {
- bool foundFactory = false;
- string schemeLower = scheme.ToLower();
- ProviderFactoryInfo pfi;
-
- // Look for a custom configuration to handle this scheme.
- string configFileName = String.Format("nmsprovider-{0}.config", schemeLower);
-
- assemblyFileName = String.Empty;
- factoryClassName = String.Empty;
-
- Tracer.DebugFormat("Attempting to locate provider configuration: {0}", configFileName);
- foreach(string path in paths)
- {
- string fullpath = Path.Combine(path, configFileName);
- Tracer.DebugFormat("Looking for: {0}", fullpath);
-
- try
- {
- if(File.Exists(fullpath))
- {
- Tracer.DebugFormat("\tConfiguration file found in {0}", fullpath);
- XmlDocument configDoc = new XmlDocument();
-
- configDoc.Load(fullpath);
- XmlElement providerNode = (XmlElement) configDoc.SelectSingleNode("/configuration/provider");
-
- if(null != providerNode)
- {
- assemblyFileName = providerNode.GetAttribute("assembly");
- factoryClassName = providerNode.GetAttribute("classFactory");
- if(!String.IsNullOrEmpty(assemblyFileName) && !String.IsNullOrEmpty(factoryClassName))
- {
- foundFactory = true;
- Tracer.DebugFormat("Selected custom provider for {0}: {1}, {2}", schemeLower, assemblyFileName, factoryClassName);
- break;
- }
- }
- }
- }
- catch(Exception ex)
- {
- Tracer.DebugFormat("Exception while scanning {0}: {1}", fullpath, ex.Message);
- }
- }
-
- if(!foundFactory)
- {
- // Check for standard provider implementations.
- if(schemaProviderFactoryMap.TryGetValue(schemeLower, out pfi))
- {
- assemblyFileName = pfi.assemblyFileName;
- factoryClassName = pfi.factoryClassName;
- foundFactory = true;
- Tracer.DebugFormat("Selected standard provider for {0}: {1}, {2}", schemeLower, assemblyFileName, factoryClassName);
- }
- }
-
- return foundFactory;
- }
-
- /// <summary>
- /// Get an array of search paths to look for config files.
- /// </summary>
- /// <returns>
- /// A collection of search paths, including the current directory, the current AppDomain's
- /// BaseDirectory and the current AppDomain's RelativeSearchPath.
- /// </returns>
- private static string[] GetConfigSearchPaths()
- {
- ArrayList pathList = new ArrayList();
-
- // Check the current folder first.
- pathList.Add("");
-#if !NETCF
- try
- {
- AppDomain currentDomain = AppDomain.CurrentDomain;
-
- // Check the folder the assembly is located in.
- Assembly executingAssembly = Assembly.GetExecutingAssembly();
- try
- {
- pathList.Add(Path.GetDirectoryName(executingAssembly.Location));
- }
- catch(Exception ex)
- {
- Tracer.DebugFormat("Error parsing executing assembly location: {0} : {1}", executingAssembly.Location, ex.Message);
- }
-
- if(null != currentDomain.BaseDirectory)
- {
- pathList.Add(currentDomain.BaseDirectory);
- }
-
- if(null != currentDomain.RelativeSearchPath)
- {
- pathList.Add(currentDomain.RelativeSearchPath);
- }
- }
- catch(Exception ex)
- {
- Tracer.DebugFormat("Error configuring search paths: {0}", ex.Message);
- }
-#endif
-
- return (string[]) pathList.ToArray(typeof(string));
- }
-
- /// <summary>
- /// Converts a <c>params object[]</c> collection into a plain <c>object[]</c>s, to pass to the constructor.
- /// </summary>
- /// <param name="firstParam">The first parameter in the collection.</param>
- /// <param name="varParams">The remaining parameters.</param>
- /// <returns>An array of <see cref="Object" /> instances.</returns>
- private static object[] MakeParameterArray(object firstParam, params object[] varParams)
- {
- ArrayList paramList = new ArrayList();
- paramList.Add(firstParam);
- foreach(object param in varParams)
- {
- paramList.Add(param);
- }
-
- return paramList.ToArray();
- }
-
- /// <summary>
- /// Creates a new connection.
- /// </summary>
- /// <returns>An <see cref="IConnection" /> created by the requested ConnectionFactory.</returns>
- public IConnection CreateConnection()
- {
- return this.factory.CreateConnection();
- }
-
- /// <summary>
- /// Creates a new connection with the given <paramref name="userName" /> and <paramref name="password" /> credentials.
- /// </summary>
- /// <param name="userName">The username to use when establishing the connection.</param>
- /// <param name="password">The password to use when establishing the connection.</param>
- /// <returns>An <see cref="IConnection" /> created by the requested ConnectionFactory.</returns>
- public IConnection CreateConnection(string userName, string password)
- {
- return this.factory.CreateConnection(userName, password);
- }
-
- /// <summary>
- /// Get/or set the broker Uri.
- /// </summary>
- public Uri BrokerUri
- {
- get { return ConnectionFactory.BrokerUri; }
- set { ConnectionFactory.BrokerUri = value; }
- }
-
- /// <summary>
- /// The actual IConnectionFactory implementation that is being used. This implementation
- /// depends on the scheme of the URI used when constructed.
- /// </summary>
- public IConnectionFactory ConnectionFactory
- {
- get { return factory; }
- }
-
- /// <summary>
- /// Get/or Set the IRedeliveryPolicy instance using the IConnectionFactory implementation
- /// that is being used.
- /// </summary>
- public IRedeliveryPolicy RedeliveryPolicy
- {
- get { return this.factory.RedeliveryPolicy; }
- set { this.factory.RedeliveryPolicy = value; }
- }
-
- /// <summary>
- /// Get/or Set the ConsumerTransformerDelegate using the IConnectionFactory implementation
- /// that is currently being used.
- /// </summary>
- public ConsumerTransformerDelegate ConsumerTransformer
- {
- get { return this.factory.ConsumerTransformer; }
- set { this.factory.ConsumerTransformer = value; }
- }
-
- /// <summary>
- /// Get/or Set the ProducerTransformerDelegate using the IConnectionFactory implementation
- /// that is currently being used.
- /// </summary>
- public ProducerTransformerDelegate ProducerTransformer
- {
- get { return this.factory.ProducerTransformer; }
- set { this.factory.ProducerTransformer = value; }
- }
- }
-}
+ }
+
+ /// <summary>
+ /// The ConnectionFactory object must define a constructor that takes as a minimum a Uri object.
+ /// Any additional parameters are optional, but will typically include a Client ID string.
+ /// </summary>
+ /// <param name="providerURI">The URI for the ActiveMQ provider.</param>
+ /// <param name="constructorParams">Optional parameters to use when creating the ConnectionFactory.</param>
+ public NMSConnectionFactory(string providerURI, params object[] constructorParams)
+ : this(URISupport.CreateCompatibleUri(providerURI), constructorParams)
+ {
+ }
+
+ /// <summary>
+ /// The ConnectionFactory object must define a constructor that takes as a minimum a Uri object.
+ /// Any additional parameters are optional, but will typically include a Client ID string.
+ /// </summary>
+ /// <param name="uriProvider">The URI for the ActiveMQ provider.</param>
+ /// <param name="constructorParams">Optional parameters to use when creating the ConnectionFactory.</param>
+ public NMSConnectionFactory(Uri uriProvider, params object[] constructorParams)
+ {
+ this.factory = CreateConnectionFactory(uriProvider, constructorParams);
+ }
+
+ /// <summary>
+ /// Create a connection factory that can create connections for the given scheme in the URI.
+ /// </summary>
+ /// <param name="uriProvider">The URI for the ActiveMQ provider.</param>
+ /// <param name="constructorParams">Optional parameters to use when creating the ConnectionFactory.</param>
+ /// <returns>A <see cref="IConnectionFactory" /> implementation that will be used.</returns>
+ public static IConnectionFactory CreateConnectionFactory(Uri uriProvider, params object[] constructorParams)
+ {
+ IConnectionFactory connectionFactory = null;
+
+ try
+ {
+ Type factoryType = GetTypeForScheme(uriProvider.Scheme);
+
+ // If an implementation was found, try to instantiate it.
+ if(factoryType != null)
+ {
+#if NETCF
+ // Compact framework does not allow the activator ta pass parameters to a constructor.
+ connectionFactory = (IConnectionFactory) Activator.CreateInstance(factoryType);
+ connectionFactory.BrokerUri = uriProvider;
+#else
+ object[] parameters = MakeParameterArray(uriProvider, constructorParams);
+ connectionFactory = (IConnectionFactory) Activator.CreateInstance(factoryType, parameters);
+#endif
+ }
+
+ if(null == connectionFactory)
+ {
+ throw new NMSConnectionException("No IConnectionFactory implementation found for connection URI: " + uriProvider);
+ }
+ }
+ catch(NMSConnectionException)
+ {
+ throw;
+ }
+ catch(Exception ex)
+ {
+ throw new NMSConnectionException("Could not create the IConnectionFactory implementation: " + ex.Message, ex);
+ }
+
+ return connectionFactory;
+ }
+
+ /// <summary>
+ /// Finds the <see cref="System.Type" /> associated with the given scheme.
+ /// </summary>
+ /// <param name="scheme">The scheme (e.g. <c>tcp</c>, <c>activemq</c> or <c>stomp</c>).</param>
+ /// <returns>The <see cref="System.Type" /> of the ConnectionFactory that will be used
+ /// to create the connection for the specified <paramref name="scheme" />.</returns>
+ private static Type GetTypeForScheme(string scheme)
+ {
+ string[] paths = GetConfigSearchPaths();
+ string assemblyFileName;
+ string factoryClassName;
+ Type factoryType = null;
+
+ Tracer.DebugFormat("Locating provider for scheme: {0}", scheme);
+ if(LookupConnectionFactoryInfo(paths, scheme, out assemblyFileName, out factoryClassName))
+ {
+ Assembly assembly = null;
+
+ Tracer.DebugFormat("Attempting to load provider assembly: {0}", assemblyFileName);
+ try
+ {
+ assembly = Assembly.Load(assemblyFileName);
+ if(null != assembly)
+ {
+ Tracer.Debug("Succesfully loaded provider.");
+ }
+ }
+ catch(Exception ex)
+ {
+ Tracer.ErrorFormat("Exception loading assembly failed: {0}", ex.Message);
+ assembly = null;
+ }
+
+ if(null == assembly)
+ {
+ foreach(string path in paths)
+ {
+ string fullpath = Path.Combine(path, assemblyFileName) + ".dll";
+
+ Tracer.DebugFormat("Looking for: {0}", fullpath);
+ if(File.Exists(fullpath))
+ {
+ Tracer.Debug("\tAssembly found! Attempting to load...");
+ try
+ {
+ assembly = Assembly.LoadFrom(fullpath);
+ }
+ catch(Exception ex)
+ {
+ Tracer.ErrorFormat("Exception loading assembly failed: {0}", ex.Message);
+ assembly = null;
+ }
+
+ if(null != assembly)
+ {
+ Tracer.Debug("Successfully loaded provider.");
+ break;
+ }
+
+ Tracer.Debug("Failed to load provider. Continuing search...");
+ }
+ }
+ }
+
+ if(null != assembly)
+ {
+#if NETCF
+ factoryType = assembly.GetType(factoryClassName, true);
+#else
+ factoryType = assembly.GetType(factoryClassName, true, true);
+#endif
+ if(null == factoryType)
+ {
+ Tracer.Fatal("Failed to load class factory from provider.");
+ }
+ }
+ else
+ {
+ Tracer.Fatal("Failed to load provider assembly.");
+ }
+ }
+
+ return factoryType;
+ }
+
+ /// <summary>
+ /// Lookup the connection factory assembly filename and class name.
+ /// Read an external configuration file that maps scheme to provider implementation.
+ /// Load XML config files named: nmsprovider-{scheme}.config
+ /// Following is a sample configuration file named nmsprovider-jms.config. Replace
+ /// the parenthesis with angle brackets for proper XML formatting.
+ ///
+ /// (?xml version="1.0" encoding="utf-8" ?)
+ /// (configuration)
+ /// (provider assembly="MyCompany.NMS.JMSProvider.dll" classFactory="MyCompany.NMS.JMSProvider.ConnectionFactory"/)
+ /// (/configuration)
+ ///
+ /// This configuration file would be loaded and parsed when a connection uri with a scheme of 'jms'
+ /// is used for the provider. In this example the connection string might look like:
+ /// jms://localhost:7222
+ ///
+ /// </summary>
+ /// <param name="paths">Folder paths to look in.</param>
+ /// <param name="scheme">The scheme.</param>
+ /// <param name="assemblyFileName">Name of the assembly file.</param>
+ /// <param name="factoryClassName">Name of the factory class.</param>
+ /// <returns><c>true</c> if the configuration file for the specified <paramref name="scheme" /> could
+ /// be found; otherwise, <c>false</c>.</returns>
+ private static bool LookupConnectionFactoryInfo(string[] paths, string scheme, out string assemblyFileName, out string factoryClassName)
+ {
+ bool foundFactory = false;
+ string schemeLower = scheme.ToLower();
+ ProviderFactoryInfo pfi;
+
+ // Look for a custom configuration to handle this scheme.
+ string configFileName = String.Format("nmsprovider-{0}.config", schemeLower);
+
+ assemblyFileName = String.Empty;
+ factoryClassName = String.Empty;
+
+ Tracer.DebugFormat("Attempting to locate provider configuration: {0}", configFileName);
+ foreach(string path in paths)
+ {
+ string fullpath = Path.Combine(path, configFileName);
+ Tracer.DebugFormat("Looking for: {0}", fullpath);
+
+ try
+ {
+ if(File.Exists(fullpath))
+ {
+ Tracer.DebugFormat("\tConfiguration file found in {0}", fullpath);
+ XmlDocument configDoc = new XmlDocument();
+
+ configDoc.Load(fullpath);
+ XmlElement providerNode = (XmlElement) configDoc.SelectSingleNode("/configuration/provider");
+
+ if(null != providerNode)
+ {
+ assemblyFileName = providerNode.GetAttribute("assembly");
+ factoryClassName = providerNode.GetAttribute("classFactory");
+ if(!String.IsNullOrEmpty(assemblyFileName) && !String.IsNullOrEmpty(factoryClassName))
+ {
+ foundFactory = true;
+ Tracer.DebugFormat("Selected custom provider for {0}: {1}, {2}", schemeLower, assemblyFileName, factoryClassName);
+ break;
+ }
+ }
+ }
+ }
+ catch(Exception ex)
+ {
+ Tracer.DebugFormat("Exception while scanning {0}: {1}", fullpath, ex.Message);
+ }
+ }
+
+ if(!foundFactory)
+ {
+ // Check for standard provider implementations.
+ if(schemaProviderFactoryMap.TryGetValue(schemeLower, out pfi))
+ {
+ assemblyFileName = pfi.assemblyFileName;
+ factoryClassName = pfi.factoryClassName;
+ foundFactory = true;
+ Tracer.DebugFormat("Selected standard provider for {0}: {1}, {2}", schemeLower, assemblyFileName, factoryClassName);
+ }
+ }
+
+ return foundFactory;
+ }
+
+ /// <summary>
+ /// Get an array of search paths to look for config files.
+ /// </summary>
+ /// <returns>
+ /// A collection of search paths, including the current directory, the current AppDomain's
+ /// BaseDirectory and the current AppDomain's RelativeSearchPath.
+ /// </returns>
+ private static string[] GetConfigSearchPaths()
+ {
+ ArrayList pathList = new ArrayList();
+
+ // Check the current folder first.
+ pathList.Add("");
+#if !NETCF
+ try
+ {
+ AppDomain currentDomain = AppDomain.CurrentDomain;
+
+ // Check the folder the assembly is located in.
+ Assembly executingAssembly = Assembly.GetExecutingAssembly();
+ try
+ {
+ var path = Path.GetDirectoryName(executingAssembly.Location);
+ if (!string.IsNullOrEmpty(path))
+ {
+ pathList.Add(path);
+ }
+ }
+ catch(Exception ex)
+ {
+ Tracer.DebugFormat("Error parsing executing assembly location: {0} : {1}", executingAssembly.Location, ex.Message);
+ }
+
+ if(null != currentDomain.BaseDirectory)
+ {
+ pathList.Add(currentDomain.BaseDirectory);
+ }
+
+ if(null != currentDomain.RelativeSearchPath)
+ {
+ pathList.Add(currentDomain.RelativeSearchPath);
+ }
+ }
+ catch(Exception ex)
+ {
+ Tracer.DebugFormat("Error configuring search paths: {0}", ex.Message);
+ }
+#endif
+
+ return (string[]) pathList.ToArray(typeof(string));
+ }
+
+ /// <summary>
+ /// Converts a <c>params object[]</c> collection into a plain <c>object[]</c>s, to pass to the constructor.
+ /// </summary>
+ /// <param name="firstParam">The first parameter in the collection.</param>
+ /// <param name="varParams">The remaining parameters.</param>
+ /// <returns>An array of <see cref="Object" /> instances.</returns>
+ private static object[] MakeParameterArray(object firstParam, params object[] varParams)
+ {
+ ArrayList paramList = new ArrayList();
+ paramList.Add(firstParam);
+ foreach(object param in varParams)
+ {
+ paramList.Add(param);
+ }
+
+ return paramList.ToArray();
+ }
+
+ /// <summary>
+ /// Creates a new connection.
+ /// </summary>
+ /// <returns>An <see cref="IConnection" /> created by the requested ConnectionFactory.</returns>
+ public IConnection CreateConnection()
+ {
+ return this.factory.CreateConnection();
+ }
+
+ /// <summary>
+ /// Creates a new connection with the given <paramref name="userName" /> and <paramref name="password" /> credentials.
+ /// </summary>
+ /// <param name="userName">The username to use when establishing the connection.</param>
+ /// <param name="password">The password to use when establishing the connection.</param>
+ /// <returns>An <see cref="IConnection" /> created by the requested ConnectionFactory.</returns>
+ public IConnection CreateConnection(string userName, string password)
+ {
+ return this.factory.CreateConnection(userName, password);
+ }
+
+ /// <summary>
+ /// Get/or set the broker Uri.
+ /// </summary>
+ public Uri BrokerUri
+ {
+ get { return ConnectionFactory.BrokerUri; }
+ set { ConnectionFactory.BrokerUri = value; }
+ }
+
+ /// <summary>
+ /// The actual IConnectionFactory implementation that is being used. This implementation
+ /// depends on the scheme of the URI used when constructed.
+ /// </summary>
+ public IConnectionFactory ConnectionFactory
+ {
+ get { return factory; }
+ }
+
+ /// <summary>
+ /// Get/or Set the IRedeliveryPolicy instance using the IConnectionFactory implementation
+ /// that is being used.
+ /// </summary>
+ public IRedeliveryPolicy RedeliveryPolicy
+ {
+ get { return this.factory.RedeliveryPolicy; }
+ set { this.factory.RedeliveryPolicy = value; }
+ }
+
+ /// <summary>
+ /// Get/or Set the ConsumerTransformerDelegate using the IConnectionFactory implementation
+ /// that is currently being used.
+ /// </summary>
+ public ConsumerTransformerDelegate ConsumerTransformer
+ {
+ get { return this.factory.ConsumerTransformer; }
+ set { this.factory.ConsumerTransformer = value; }
+ }
+
+ /// <summary>
+ /// Get/or Set the ProducerTransformerDelegate using the IConnectionFactory implementation
+ /// that is currently being used.
+ /// </summary>
+ public ProducerTransformerDelegate ProducerTransformer
+ {
+ get { return this.factory.ProducerTransformer; }
+ set { this.factory.ProducerTransformer = value; }
+ }
+ }
+}