/* * 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.IO; using System.Reflection; using System.Xml; namespace Apache.NMS { /// /// Implementation of a factory for instances. /// public class NMSConnectionFactory : IConnectionFactory { protected readonly IConnectionFactory factory; /// /// 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. /// /// The URI for the ActiveMQ provider. /// Optional parameters to use when creating the ConnectionFactory. public NMSConnectionFactory(string providerURI, params object[] constructorParams) : this(new Uri(providerURI), constructorParams) { } /// /// 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. /// /// The URI for the ActiveMQ provider. /// Optional parameters to use when creating the ConnectionFactory. public NMSConnectionFactory(Uri uriProvider, params object[] constructorParams) { this.factory = CreateConnectionFactory(uriProvider, constructorParams); } /// /// Create a connection factory that can create connections for the given scheme in the URI. /// /// The URI for the ActiveMQ provider. /// Optional parameters to use when creating the ConnectionFactory. /// A implementation that will be used. 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 connectionFactory = (IConnectionFactory) Activator.CreateInstance(factoryType); #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; } /// /// Finds the associated with the given scheme. /// /// The scheme (e.g. tcp, activemq or stomp). /// The of the ConnectionFactory that will be used /// to create the connection for the specified . private static Type GetTypeForScheme(string scheme) { string[] paths = GetConfigSearchPaths(); string assemblyFileName; string factoryClassName; Type factoryType = null; Tracer.Debug("Locating provider for scheme: " + scheme); if(LookupConnectionFactoryInfo(paths, scheme, out assemblyFileName, out factoryClassName)) { Assembly assembly = null; Tracer.Debug("Attempting to locate provider assembly: " + assemblyFileName); foreach(string path in paths) { string fullpath = Path.Combine(path, assemblyFileName); Tracer.Debug("\tScanning folder: " + path); if(File.Exists(fullpath)) { Tracer.Debug("\tAssembly found!"); assembly = Assembly.LoadFrom(fullpath); break; } } if(null != assembly) { #if NETCF factoryType = assembly.GetType(factoryClassName, true); #else factoryType = assembly.GetType(factoryClassName, true, true); #endif } } return factoryType; } /// /// 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 /// /// /// Folder paths to look in. /// The scheme. /// Name of the assembly file. /// Name of the factory class. /// true if the configuration file for the specified could /// be found; otherwise, false. private static bool LookupConnectionFactoryInfo(string[] paths, string scheme, out string assemblyFileName, out string factoryClassName) { string configFileName = String.Format("nmsprovider-{0}.config", scheme.ToLower()); bool foundFactory = false; assemblyFileName = String.Empty; factoryClassName = String.Empty; Tracer.Debug("Attempting to locate provider configuration: " + configFileName); foreach(string path in paths) { string fullpath = Path.Combine(path, configFileName); Tracer.Debug("\tScanning folder: " + path); try { if(File.Exists(fullpath)) { Tracer.Debug("\tConfiguration file found!"); 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.Empty != assemblyFileName && String.Empty != factoryClassName) { foundFactory = true; break; } } } } catch { } } return foundFactory; } /// /// Get an array of search paths to look for config files. /// /// /// A collection of search paths, including the current directory, the current AppDomain's /// BaseDirectory and the current AppDomain's RelativeSearchPath. /// private static string[] GetConfigSearchPaths() { ArrayList pathList = new ArrayList(); // Check the current folder first. pathList.Add(""); #if !NETCF AppDomain currentDomain = AppDomain.CurrentDomain; // Check the folder the assembly is located in. pathList.Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); if(null != currentDomain.BaseDirectory) { pathList.Add(currentDomain.BaseDirectory); } if(null != currentDomain.RelativeSearchPath) { pathList.Add(currentDomain.RelativeSearchPath); } #endif return (string[]) pathList.ToArray(typeof(string)); } /// /// Converts a params object[] collection into a plain object[]s, to pass to the constructor. /// /// The first parameter in the collection. /// The remaining parameters. /// An array of instances. 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(); } /// /// Creates a new connection. /// /// An created by the requested ConnectionFactory. public IConnection CreateConnection() { return this.factory.CreateConnection(); } /// /// Creates a new connection with the given and credentials. /// /// The username to use when establishing the connection. /// The password to use when establishing the connection. /// An created by the requested ConnectionFactory. public IConnection CreateConnection(string userName, string password) { return this.factory.CreateConnection(userName, password); } /// /// The actual IConnectionFactory implementation that is being used. This implementation /// depends on the scheme of the URI used when constructed. /// public IConnectionFactory ConnectionFactory { get { return factory; } } } }