#region Disclaimer / License
// Copyright (C) 2010, Jackie Ng
// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Reflection;
using System.Collections.Specialized;
using System.Data.Common;
namespace OSGeo.MapGuide.MaestroAPI
{
///
/// Represents an entry in the Connection Provider Registry
///
public class ConnectionProviderEntry
{
///
/// Gets or sets the name.
///
/// The name.
public string Name { get; private set; }
///
/// Gets or sets the description.
///
/// The description.
public string Description { get; private set; }
///
/// Gets or sets a value indicating whether this instance is multi platform.
///
///
/// true if this instance is multi platform; otherwise, false.
///
public bool IsMultiPlatform { get; private set; }
internal ConnectionProviderEntry(string name, string desc, bool multiPlatform)
{
this.Name = name;
this.Description = desc;
this.IsMultiPlatform = multiPlatform;
}
}
///
/// The entry point of the Maestro API. The is used to create
/// objects. is the root object of the Maestro API, and is where most of the functionality provided
/// by this API is accessed from.
///
/// The supports dynamic creation of objects given a provider name
/// and a connection string, which specifies the initialization parameters of the connection. The connection providers are defined in an XML
/// file called ConnectionProviders.xml which contains all the registered providers. Each provider has the following properties:
///
/// 1. The name of the provider
/// 2. The assembly containing the implementation
/// 3. The name of this implementation.
///
/// The implementation is expected to have a non-public constructor which takes a single parameter,
/// a containing the initialization parameters parsed from the given connection
/// string.
///
///
/// This example shows how to create a http-based MapGuide Server connection to the server's mapagent interface.
///
/// using OSGeo.MapGuide.MaestroAPI;
///
/// ...
///
/// IServerConnection conn = ConnectionProviderRegistry.CreateConnection("Maestro.Http",
/// "Url", "http://localhost/mapguide/mapagent/mapagent.fcgi",
/// "Username", "Administrator",
/// "Password", "admin");
///
///
///
///
/// This example shows how to create a TCP/IP connection that wraps the official MapGuide API
///
/// using OSGeo.MapGuide.MaestroAPI;
///
/// ...
///
/// IServerConnection conn = ConnectionProviderRegistry.CreateConnection("Maestro.LocalNative",
/// "ConfigFile", "webconfig.ini",
/// "Username", "Administrator",
/// "Password", "admin");
///
///
public sealed class ConnectionProviderRegistry
{
const string PROVIDER_CONFIG = "ConnectionProviders.xml";
static Dictionary _ctors;
static List _providers;
static string _dllRoot;
static ConnectionProviderRegistry()
{
_ctors = new Dictionary();
_providers = new List();
var dir = System.IO.Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
var path = System.IO.Path.Combine(dir, PROVIDER_CONFIG);
_dllRoot = System.IO.Path.GetDirectoryName(path);
XmlDocument doc = new XmlDocument();
doc.Load(path);
XmlNodeList providers = doc.SelectNodes("//ConnectionProviderRegistry/ConnectionProvider");
foreach (XmlNode prov in providers)
{
string name = prov["Name"].InnerText.ToUpper();
string desc = prov["Description"].InnerText;
string dll = prov["Assembly"].InnerText;
string type = prov["Type"].InnerText;
if (!System.IO.Path.IsPathRooted(dll))
dll = System.IO.Path.Combine(_dllRoot, dll);
try
{
Assembly asm = Assembly.LoadFrom(dll);
MaestroApiProviderAttribute[] attr = asm.GetCustomAttributes(typeof(MaestroApiProviderAttribute), true) as MaestroApiProviderAttribute[];
if (attr != null && attr.Length == 1)
{
name = attr[0].Name.ToUpper();
desc = attr[0].Description;
_ctors[name] = attr[0].ImplType;
_providers.Add(new ConnectionProviderEntry(name, desc, attr[0].IsMultiPlatform));
}
}
catch
{
}
}
}
internal static NameValueCollection ParseConnectionString(string connectionString)
{
var builder = new DbConnectionStringBuilder();
builder.ConnectionString = connectionString;
NameValueCollection values = new NameValueCollection();
foreach (string key in builder.Keys)
{
values.Add(key, builder[key].ToString());
}
return values;
}
///
/// Gets a list of registered provider names. The returned names are in upper-case.
///
///
public static ConnectionProviderEntry[] GetProviders()
{
return _providers.ToArray();
}
///
/// Creates an initialized object given the provider name and connection string
///
///
///
///
public static IServerConnection CreateConnection(string provider, string connectionString)
{
string name = provider.ToUpper();
if (!_ctors.ContainsKey(name))
throw new ArgumentException("Provider not registered: " + provider);
ConnectionProviderEntry prv = FindProvider(provider);
if (prv != null && !prv.IsMultiPlatform && Platform.IsRunningOnMono)
throw new NotSupportedException("The specified provider is not usable in your operating system");
Type t = _ctors[name];
NameValueCollection initParams = ParseConnectionString(connectionString);
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance;
IServerConnection conn = (IServerConnection)t.InvokeMember(null, flags, null, null, new object[] { initParams });
return conn;
}
///
/// Creates an initialized object given the provider name and the initalization parameters
///
///
///
///
public static IServerConnection CreateConnection(string provider, NameValueCollection connInitParams)
{
string name = provider.ToUpper();
if (!_ctors.ContainsKey(name))
throw new ArgumentException("Provider not registered: " + provider);
ConnectionProviderEntry prv = FindProvider(provider);
if (prv != null && !prv.IsMultiPlatform && Platform.IsRunningOnMono)
throw new NotSupportedException("The specified provider is not usable in your operating system");
Type t = _ctors[name];
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance;
IServerConnection conn = (IServerConnection)t.InvokeMember(null, flags, null, null, new object[] { connInitParams });
return conn;
}
///
/// Creates an initialized object given the provider name and the initalization parameters.
///
///
/// A variable list of initialization parameters. They must be specified in the form: [Param1], [Value1], [Param2], [Value2], etc
///
public static IServerConnection CreateConnection(string provider, params string[] initParameters)
{
var initP = new NameValueCollection();
for (int i = 0; i < initParameters.Length; i += 2)
{
string name = null;
string value = null;
if (i < initParameters.Length - 1)
name = initParameters[i];
if (i + 1 <= initParameters.Length - 1)
value = initParameters[i + 1];
if (name != null)
initP[name] = value ?? string.Empty;
}
return CreateConnection(provider, initP);
}
private static ConnectionProviderEntry FindProvider(string provider)
{
foreach (var prv in _providers)
{
if (prv.Name == provider)
return prv;
}
return null;
}
}
}