// $Id$ // // Copyright 2007-2008 Cisco Systems Inc. // // Licensed 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 Etch.Transport; using Etch.Util; namespace Etch.Support { /// /// Interface to transport factory /// public abstract class TransportFactory { /// /// Constructs a new Transport stack topped by a DeliveryService /// which is used by the remote service implementations to send /// messages and make calls. /// /// transport configuration parameters. /// additional resources needed by the stack. /// the DeliveryService topping the transport stack. protected abstract DeliveryService NewTransport( string uri, Resources resources ); /// /// Constructs a new Transport stack topped by a DeliveryService /// which is used by the remote service implementations to send /// messages and make calls. /// /// transport configuration parameters. /// additional resources needed by the stack. /// the DeliveryService topping the transport stack. public static DeliveryService GetTransport( string uri,Resources resources ) { URL u = new URL( uri ); TransportFactory f = GetTransportFactory( u.Scheme ); return f.NewTransport( uri, resources ); } /// /// Constructs a new Transport Listener which is used to construct /// server sessions. /// /// listener configuration parameters. /// additional resources needed by the listener. /// constructs the actual service class instances. /// an out-of-band source which may be used to control the listener. protected abstract Transport NewListener(string uri, Resources resources, ServerFactory factory); /// /// Constructs a new Transport Listener which is used to construct /// server sessions. /// /// listener configuration parameters. /// additional resources needed by the listener. /// constructs the actual service class instances. /// an out-of-band source which may be used to control the listener. public static Transport GetListener( string uri, Resources resources, ServerFactory factory ) { URL u = new URL( uri ); TransportFactory f = GetTransportFactory( u.Scheme ); return f.NewListener( uri, resources, factory ); } /// /// 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. /// /// /// /// /// the most recently added filter 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; } /// /// 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 /// 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) }; /// /// Gets the fully qualified type name of the filter. /// /// /// the fully qualified type name of the filter. public static string GetFilter(string name) { lock (filters) { string value; return filters.TryGetValue(name, out value) ? value : null; } } /// /// Sets the fully qualified type name of the filter. /// /// /// public static void DefineFilter(string name, string typeName) { lock (filters) { filters.Add(name, typeName); } } private static readonly Dictionary filters = new Dictionary(); /// /// Gets the named transport factory. /// /// the name of a configured transport factory. /// the named transport factory. 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; } } /// /// Puts a named transport factory. /// /// the uri scheme of this transport factory. /// 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. public static void Define( string name, object tfspec ) { lock (transportFactories) { transportFactories.Add(name, tfspec); } } private readonly static Dictionary transportFactories = new Dictionary(); static TransportFactory() { Define("tcp", new TcpTransportFactory(false)); Define("tls", new TcpTransportFactory(true)); DefineFilter("KeepAlive", "Etch.Transport.Filter.KeepAlive"); DefineFilter("PwAuth", "Etch.Transport.Filter.PwAuth"); DefineFilter("Logger", "Etch.Transport.Filter.Logger"); } } }