blob: 9523583519b1841ab0a871c23318ca1a46217f10 [file] [log] [blame]
// $Id$
//
// 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.Generic;
using System.IO;
using System.Reflection;
using Org.Apache.Etch.Bindings.Csharp.Transport;
using Org.Apache.Etch.Bindings.Csharp.Util;
namespace Org.Apache.Etch.Bindings.Csharp.Support
{
/// <summary>
/// Interface to transport factory
/// </summary>
public abstract class TransportFactory
{
/// <summary>
/// Constructs a new Transport stack topped by a TransportMessage
/// which is used by the remote service implementations to send
/// messages.
/// </summary>
/// <param name="uri">transport configuration parameters.</param>
/// <param name="resources">additional resources needed by the stack.</param>
/// <returns>the TransportMessage topping the transport stack.</returns>
protected abstract TransportMessage NewTransport(string uri, Resources resources);
/// <summary>
/// Constructs a new Transport stack topped by a TransportMessage
/// which is used by the remote service implementations to send
/// messages.
/// </summary>
/// <param name="uri">transport configuration parameters.</param>
/// <param name="resources">additional resources needed by the stack.</param>
/// <returns>the TransportMessage topping the transport stack.</returns>
public static TransportMessage GetTransport(string uri, Resources resources)
{
URL u = new URL(uri);
TransportFactory f = GetTransportFactory(u.Scheme);
return f.NewTransport(uri, resources);
}
/// <summary>
/// Constructs a new Transport Listener which is used to construct
/// server sessions.
/// </summary>
/// <param name="uri">listener configuration parameters.</param>
/// <param name="resources">additional resources needed by the listener.</param>
/// <returns>an out-of-band source which may be used to control the listener.</returns>
protected abstract Transport<ServerFactory> NewListener(string uri, Resources resources);
/// <summary>
/// Constructs a new Transport Listener which is used to construct
/// server sessions.
/// </summary>
/// <param name="uri">listener configuration parameters.</param>
/// <param name="resources">additional resources needed by the listener.</param>
/// <returns>an out-of-band source which may be used to control the listener.</returns>
public static Transport<ServerFactory> GetListener(string uri, Resources resources)
{
URL u = new URL(uri);
TransportFactory f = GetTransportFactory(u.Scheme);
return f.NewListener(uri, resources);
}
/// <summary>
/// Adds any message filters specified on the uri. They are added in order
/// from transport to session. The first filter is the session for Messagizer,
/// the second is the session for the first, etc. The last filter added is
/// returned, and becomes the TransportMessage for what follows.
/// </summary>
/// <param name="transport"></param>
/// <param name="uri"></param>
/// <param name="resources"></param>
/// <returns>the most recently added filter</returns>
protected TransportMessage AddFilters(TransportMessage transport, URL uri, Resources resources)
{
string s = uri.GetTerm(FILTER);
if (s == null || s.Length == 0)
return transport;
StringTokenizer st = new StringTokenizer(s, ",:;| \t\r\n");
while (st.HasMoreTokens())
{
string t = st.NextToken();
transport = AddFilter(transport, t, uri, resources);
}
return transport;
}
/// <summary>
/// Query term on the transport uri which defines a set of filters which
/// process messages as they move up and down the transport stack. Filter
/// names are separated by one or more of these characters: ",:;| \t\r\n".
///
/// Usage example: tcp://host:port?filter=KeepAlive,PwAuth
/// </summary>
public const string FILTER = "filter";
private TransportMessage AddFilter(TransportMessage transport, string name,
URL uri, Resources resources)
{
string typeName = GetFilter(name);
if (typeName == null)
throw new ArgumentException(
string.Format( "Class '{0}' for filter name '{1}' not defined", typeName, name ) );
Type type = Type.GetType(typeName);
ConstructorInfo c = type.GetConstructor(FILTER_PARAMS);
return (TransportMessage) c.Invoke(new object[] { transport, uri, resources });
}
private readonly static Type[] FILTER_PARAMS = { typeof(TransportMessage), typeof(URL), typeof(Resources) };
/// <summary>
/// Gets the fully qualified type name of the filter.
/// </summary>
/// <param name="name"></param>
/// <returns>the fully qualified type name of the filter.</returns>
public static string GetFilter(string name)
{
lock (filters)
{
string value;
return filters.TryGetValue(name, out value) ? value : null;
}
}
/// <summary>
/// Sets the fully qualified type name of the filter.
/// </summary>
/// <param name="name"></param>
/// <param name="typeName"></param>
public static void DefineFilter(string name, string typeName)
{
lock (filters)
{
filters.Add(name, typeName);
}
}
private static readonly Dictionary<string, string> filters =
new Dictionary<string, string>();
/// <summary>
/// Gets the named transport factory.
/// </summary>
/// <param name="name">the name of a configured transport factory.</param>
/// <returns>the named transport factory.</returns>
private static TransportFactory GetTransportFactory( string name )
{
object tfspec = Get(name);
if (tfspec == null)
throw new IOException("transport factory scheme '" + name + "' unknown");
if (tfspec is string)
tfspec = Type.GetType((string)tfspec);
if (tfspec is Type)
{
ConstructorInfo c = ((Type)tfspec).GetConstructor(FACTORY_PARAMS);
tfspec = c.Invoke(FACTORY_ARGS);
}
if (tfspec is TransportFactory)
return (TransportFactory)tfspec;
throw new ArgumentException(String.Format(
"Cannot create an instance of TransportFactory from transport factory name '{0}'", name));
}
private readonly static Type[] FACTORY_PARAMS = { };
private readonly static object[] FACTORY_ARGS = { };
public static object Get(string name)
{
lock (transportFactories)
{
object value;
return transportFactories.TryGetValue(name, out value) ? value : null;
}
}
/// <summary>
/// Puts a named transport factory.
/// </summary>
/// <param name="name">the uri scheme of this transport factory.</param>
/// <param name="tfspec">the transport factory spec to associate with the
/// name. This can be an instance of TransportFactory or the name of a subclass
/// of TransportFactory to instantiate.</param>
public static void Define( string name, object tfspec )
{
lock (transportFactories)
{
transportFactories.Add(name, tfspec);
}
}
private readonly static Dictionary<string, object> transportFactories =
new Dictionary<string, object>();
static TransportFactory()
{
Define("tcp", new TcpTransportFactory(false));
Define("tls", new TcpTransportFactory(true));
DefineFilter("KeepAlive", "Org.Apache.Etch.Bindings.Csharp.Transport.Filter.KeepAlive");
DefineFilter("PwAuth", "Org.Apache.Etch.Bindings.Csharp.Transport.Filter.PwAuth");
DefineFilter("Logger", "Org.Apache.Etch.Bindings.Csharp.Transport.Filter.Logger");
}
}
}