#region License
/*
* Copyright 2002-2004 the original author or authors.
*
* 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.
*/
#endregion
using System;
using System.Collections;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using Spring.Context.Support;
using Spring.Core.TypeResolution;
using Spring.Util;
using Spring.Reflection.Dynamic;
namespace Spring.Core.IO{
/// <summary>
/// Registry class that allows users to register and retrieve protocol handlers.
/// </summary>
/// <remarks>
/// <para>
/// Resource handler is an implementation of <see cref="IResource"/> interface
/// that should be used to process resources with the specified protocol.
/// </para>
/// <para>
/// They are used throughout the framework to access resources from various
/// sources. For example, application context loads object definitions from the resources
/// that are processed using one of the registered resource handlers.
/// </para>
/// <para>Following resource handlers are registered by default:</para>
/// <list type="table">
/// <listheader>
/// <term>Protocol</term>
/// <term>Handler Type</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <description>config</description>
/// <description><see cref="Spring.Core.IO.ConfigSectionResource"/></description>
/// <description>Resolves the resources by loading specified configuration section from the standard .NET config file.</description>
/// </item>
/// <item>
/// <description>file</description>
/// <description><see cref="Spring.Core.IO.FileSystemResource"/></description>
/// <description>Resolves filesystem resources.</description>
/// </item>
/// <item>
/// <description>http</description>
/// <description><see cref="Spring.Core.IO.UrlResource"/></description>
/// <description>Resolves remote web resources.</description>
/// </item>
/// <item>
/// <description>https</description>
/// <description><see cref="Spring.Core.IO.UrlResource"/></description>
/// <description>Resolves remote web resources via HTTPS.</description>
/// </item>
/// <item>
/// <description>ftp</description>
/// <description><see cref="Spring.Core.IO.UrlResource"/></description>
/// <description>Resolves ftp resources.</description>
/// </item>
/// <item>
/// <description>assembly</description>
/// <description><see cref="Spring.Core.IO.AssemblyResource"/></description>
/// <description>Resolves resources that are embedded into an assembly.</description>
/// </item>
/// <item>
/// <description>web</description>
/// <description><c>Spring.Core.IO.WebResource, Spring.Web</c>*</description>
/// <description>Resolves resources relative to the web application's virtual directory.</description>
/// </item>
/// </list>
/// * only available in web applications.
/// <para>
/// Users can create and register their own protocol handlers by implementing <see cref="IResource"/> interface
/// and mapping custom protocol name to that implementation. See <see cref="ResourceHandlersSectionHandler"/> for details
/// on how to register custom protocol handler.
/// </para>
/// </remarks>
/// <author>Aleksandar Seovic</author>
public class ResourceHandlerRegistry
{
/// <summary>
/// Name of the .Net config section that contains definitions
/// for custom resource handlers.
/// </summary>
private const string ResourcesSectionName = "spring/resourceHandlers";
private static IDictionary resourceHandlers = new Hashtable();
/// <summary>
/// Registers standard and user-configured resource handlers.
/// </summary>
static ResourceHandlerRegistry()
{
lock (resourceHandlers.SyncRoot)
{
RegisterResourceHandler("config", typeof(ConfigSectionResource));
RegisterResourceHandler("file", typeof(FileSystemResource));
RegisterResourceHandler("http", typeof(UrlResource));
RegisterResourceHandler("https", typeof(UrlResource));
#if NET_2_0
RegisterResourceHandler("ftp", typeof(UrlResource));
#endif
RegisterResourceHandler("assembly", typeof(AssemblyResource));
// register custom resource handlers
ConfigurationUtils.GetSection(ResourcesSectionName);
}
}
/// <summary>
/// Returns resource handler for the specified protocol name.
/// </summary>
/// <remarks>
/// <para>
/// This method returns <see cref="ConstructorInfo"/> object that should be used
/// to create an instance of the <see cref="IResource"/>-derived type by passing
/// resource location as a parameter.
/// </para>
/// </remarks>
/// <param name="protocolName">Name of the protocol to get the handler for.</param>
/// <returns>Resource handler constructor for the specified protocol name.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="protocolName"/> is <c>null</c>.</exception>
public static IDynamicConstructor GetResourceHandler(string protocolName)
{
AssertUtils.ArgumentNotNull(protocolName, "protocolName");
return (IDynamicConstructor)resourceHandlers[protocolName];
}
/// <summary>
/// Returns <c>true</c> if a handler is registered for the specified protocol,
/// <c>false</c> otherwise.
/// </summary>
/// <param name="protocolName">Name of the protocol.</param>
/// <returns>
/// <c>true</c> if a handler is registered for the specified protocol, <c>false</c> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException">If <paramref name="protocolName"/> is <c>null</c>.</exception>
public static bool IsHandlerRegistered(string protocolName)
{
return resourceHandlers.Contains(protocolName);
}
/// <summary>
/// Registers resource handler and maps it to the specified protocol name.
/// </summary>
/// <remarks>
/// <p>
/// If the mapping already exists, the existing mapping will be
/// silently overwritten with the new mapping.
/// </p>
/// </remarks>
/// <param name="protocolName">
/// The protocol to add (or override).
/// </param>
/// <param name="handlerTypeName">
/// The type name of the concrete implementation of the
/// <see cref="Spring.Core.IO.IResource"/> interface that will handle
/// the specified protocol.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="protocolName"/> is
/// <see langword="null"/> or contains only whitespace character(s); or
/// if the supplied <paramref name="handlerTypeName"/> is
/// <see langword="null"/>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// If the supplied <paramref name="handlerTypeName"/> is not a
/// <see cref="Type"/> that derives from the
/// <see cref="Spring.Core.IO.IResource"/> interface; or (having passed
/// this first check), the supplied <paramref name="handlerTypeName"/>
/// does not expose a constructor that takes a single
/// <see cref="System.String"/> parameter.
/// </exception>
public static void RegisterResourceHandler(string protocolName, string handlerTypeName)
{
AssertUtils.ArgumentHasText(protocolName, "protocolName");
AssertUtils.ArgumentHasText(handlerTypeName, "handlerTypeName");
Type handlerType = TypeResolutionUtils.ResolveType(handlerTypeName);
RegisterResourceHandler(protocolName, handlerType);
}
/// <summary>
/// Registers resource handler and maps it to the specified protocol name.
/// </summary>
/// <remarks>
/// <p>
/// If the mapping already exists, the existing mapping will be
/// silently overwritten with the new mapping.
/// </p>
/// </remarks>
/// <param name="protocolName">
/// The protocol to add (or override).
/// </param>
/// <param name="handlerType">
/// The concrete implementation of the
/// <see cref="Spring.Core.IO.IResource"/> interface that will handle
/// the specified protocol.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="protocolName"/> is
/// <see langword="null"/> or contains only whitespace character(s); or
/// if the supplied <paramref name="handlerType"/> is
/// <see langword="null"/>.
/// </exception>
/// <exception cref="System.ArgumentException">
/// If the supplied <paramref name="handlerType"/> is not a
/// <see cref="Type"/> that derives from the
/// <see cref="Spring.Core.IO.IResource"/> interface; or (having passed
/// this first check), the supplied <paramref name="handlerType"/>
/// does not expose a constructor that takes a single
/// <see cref="System.String"/> parameter.
/// </exception>
public static void RegisterResourceHandler(string protocolName, Type handlerType)
{
#region Sanity Checks
AssertUtils.ArgumentHasText(protocolName, "protocolName");
AssertUtils.ArgumentNotNull(handlerType, "handlerType");
if (!typeof(IResource).IsAssignableFrom(handlerType))
{
throw new ArgumentException(
string.Format("[{0}] does not implement [{1}] interface (it must).", handlerType.FullName, typeof(IResource).FullName));
}
#endregion
lock (resourceHandlers.SyncRoot)
{
#if NET_2_0
SecurityCritical.ExecutePrivileged( new SecurityPermission(SecurityPermissionFlag.Infrastructure), delegate
{
// register generic uri parser for this scheme
if (!UriParser.IsKnownScheme(protocolName))
{
UriParser.Register(new TolerantUriParser(), protocolName, 0);
}
});
#endif
IDynamicConstructor ctor = GetResourceConstructor(handlerType);
resourceHandlers[protocolName] = ctor;
}
}
#if NET_2_0
/// <summary>
/// Allows to create any arbitrary Url format
/// </summary>
private class TolerantUriParser : GenericUriParser
{
private const GenericUriParserOptions DefaultOptions = GenericUriParserOptions.Default
| GenericUriParserOptions.GenericAuthority
| GenericUriParserOptions.AllowEmptyAuthority;
public TolerantUriParser()
: base(DefaultOptions)
{ }
}
#endif
private static IDynamicConstructor GetResourceConstructor(Type handlerType)
{
ConstructorInfo ctor = handlerType.GetConstructor(new Type[] { typeof(string) });
if (ctor == null)
{
throw new ArgumentException(
string.Format("[{0}] does not have a constructor that takes a single string as an argument (it must).", handlerType.FullName));
}
return new SafeConstructor(ctor);
}
}
}
|