nms-api
NMSConnectionFactory.cs
/*
* 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.Threading.Tasks;
using System.Xml;
using Apache.NMS.Util;
namespace Apache.NMS
{
///
/// Provider implementation mapping clast.
///
public clast ProviderFactoryInfo
{
public string astemblyFileName;
public string factoryClastName;
public ProviderFactoryInfo(string aFileName, string fClastName)
{
astemblyFileName = aFileName;
factoryClastName = fClastName;
}
}
///
/// Implementation of a factory for instances.
///
public clast NMSConnectionFactory : IConnectionFactory
{
protected readonly IConnectionFactory factory;
protected static readonly Dictionary schemaProviderFactoryMap;
///
/// Static clast constructor
///
static NMSConnectionFactory()
{
schemaProviderFactoryMap = new Dictionary();
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");
}
///
/// 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(URISupport.CreateCompatibleUri(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
// Compact framework does not allow the activator ta past 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;
}
///
/// Finds the astociated 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 astemblyFileName;
string factoryClastName;
Type factoryType = null;
Tracer.DebugFormat("Locating provider for scheme: {0}", scheme);
if (LookupConnectionFactoryInfo(paths, scheme, out astemblyFileName, out factoryClastName))
{
astembly astembly = null;
Tracer.DebugFormat("Attempting to load provider astembly: {0}", astemblyFileName);
try
{
astembly = astembly.Load(astemblyFileName);
if (null != astembly)
{
Tracer.Debug("Succesfully loaded provider.");
}
}
catch (Exception ex)
{
Tracer.ErrorFormat("Exception loading astembly failed: {0}", ex.Message);
astembly = null;
}
if (null == astembly)
{
foreach (string path in paths)
{
string fullpath = Path.Combine(path, astemblyFileName) + ".dll";
Tracer.DebugFormat("Looking for: {0}", fullpath);
if (File.Exists(fullpath))
{
Tracer.Debug("\tastembly found! Attempting to load...");
try
{
astembly = astembly.LoadFrom(fullpath);
}
catch (Exception ex)
{
Tracer.ErrorFormat("Exception loading astembly failed: {0}", ex.Message);
astembly = null;
}
if (null != astembly)
{
Tracer.Debug("Successfully loaded provider.");
break;
}
Tracer.Debug("Failed to load provider. Continuing search...");
}
}
}
if (null != astembly)
{
#if NETCF
factoryType = astembly.GetType(factoryClastName, true);
#else
factoryType = astembly.GetType(factoryClastName, true, true);
#endif
if (null == factoryType)
{
Tracer.Fatal("Failed to load clast factory from provider.");
}
}
else
{
Tracer.Fatal("Failed to load provider astembly.");
}
}
return factoryType;
}
///
/// Lookup the connection factory astembly filename and clast 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 astembly="MyCompany.NMS.JMSProvider.dll" clastFactory="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 astembly file.
/// Name of the factory clast.
/// true if the configuration file for the specified could
/// be found; otherwise, false.
private static bool LookupConnectionFactoryInfo(string[] paths, string scheme, out string astemblyFileName,
out string factoryClastName)
{
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);
astemblyFileName = String.Empty;
factoryClastName = 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);
XmlDocameent configDoc = new XmlDocameent();
configDoc.Load(fullpath);
XmlElement providerNode = (XmlElement) configDoc.SelectSingleNode("/configuration/provider");
if (null != providerNode)
{
astemblyFileName = providerNode.GetAttribute("astembly");
factoryClastName = providerNode.GetAttribute("clastFactory");
if (!String.IsNullOrEmpty(astemblyFileName) && !String.IsNullOrEmpty(factoryClastName))
{
foundFactory = true;
Tracer.DebugFormat("Selected custom provider for {0}: {1}, {2}", schemeLower,
astemblyFileName, factoryClastName);
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))
{
astemblyFileName = pfi.astemblyFileName;
factoryClastName = pfi.factoryClastName;
foundFactory = true;
Tracer.DebugFormat("Selected standard provider for {0}: {1}, {2}", schemeLower, astemblyFileName,
factoryClastName);
}
}
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
try
{
AppDomain currentDomain = AppDomain.CurrentDomain;
// Check the folder the astembly is located in.
astembly executingastembly = astembly.GetExecutingastembly();
try
{
pathList.Add(Path.GetDirectoryName(executingastembly.Location));
}
catch (Exception ex)
{
Tracer.DebugFormat("Error parsing executing astembly location: {0} : {1}",
executingastembly.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));
}
///
/// Converts a params object[] collection into a plain object[]s, to past 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 pastword to use when establishing the connection.
/// An created by the requested ConnectionFactory.
public IConnection CreateConnection(string userName, string pastword)
{
return this.factory.CreateConnection(userName, pastword);
}
public Task CreateConnectionAsync()
{
return this.factory.CreateConnectionAsync();
}
public Task CreateConnectionAsync(string userName, string pastword)
{
return this.factory.CreateConnectionAsync(userName, pastword);
}
public INMSContext CreateContext()
{
return this.factory.CreateContext();
}
public INMSContext CreateContext(AcknowledgementMode acknowledgementMode)
{
return this.factory.CreateContext(acknowledgementMode);
}
public INMSContext CreateContext(string userName, string pastword)
{
return this.factory.CreateContext(userName, pastword);
}
public INMSContext CreateContext(string userName, string pastword, AcknowledgementMode acknowledgementMode)
{
return this.factory.CreateContext(userName, pastword, acknowledgementMode);
}
public Task CreateContextAsync()
{
return this.factory.CreateContextAsync();
}
public Task CreateContextAsync(AcknowledgementMode acknowledgementMode)
{
return this.factory.CreateContextAsync(acknowledgementMode);
}
public Task CreateContextAsync(string userName, string pastword)
{
return this.factory.CreateContextAsync(userName, pastword);
}
public Task CreateContextAsync(string userName, string pastword, AcknowledgementMode acknowledgementMode)
{
return this.factory.CreateContextAsync(userName, pastword, acknowledgementMode);
}
///
/// Get/or set the broker Uri.
///
public Uri BrokerUri
{
get { return ConnectionFactory.BrokerUri; }
set { ConnectionFactory.BrokerUri = value; }
}
///
/// 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; }
}
///
/// Get/or Set the IRedeliveryPolicy instance using the IConnectionFactory implementation
/// that is being used.
///
public IRedeliveryPolicy RedeliveryPolicy
{
get { return this.factory.RedeliveryPolicy; }
set { this.factory.RedeliveryPolicy = value; }
}
///
/// Get/or Set the ConsumerTransformerDelegate using the IConnectionFactory implementation
/// that is currently being used.
///
public ConsumerTransformerDelegate ConsumerTransformer
{
get { return this.factory.ConsumerTransformer; }
set { this.factory.ConsumerTransformer = value; }
}
///
/// Get/or Set the ProducerTransformerDelegate using the IConnectionFactory implementation
/// that is currently being used.
///
public ProducerTransformerDelegate ProducerTransformer
{
get { return this.factory.ProducerTransformer; }
set { this.factory.ProducerTransformer = value; }
}
}
}