blob: dd46f6d591d01d048029d97ada0a9be69dbeae5e [file] [log] [blame]
#region Apache License
//
// 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.
//
#endregion
using System;
using System.Collections;
using System.Reflection;
using log4net.Appender;
using log4net.Util;
using log4net.Repository;
namespace log4net.Core
{
/// <summary>
/// The implementation of the <see cref="IRepositorySelector"/> interface suitable
/// for use with the compact framework
/// </summary>
/// <remarks>
/// <para>
/// This <see cref="IRepositorySelector"/> implementation is a simple
/// mapping between repository name and <see cref="ILoggerRepository"/>
/// object.
/// </para>
/// <para>
/// The .NET Compact Framework 1.0 does not support retrieving assembly
/// level attributes therefore unlike the <c>DefaultRepositorySelector</c>
/// this selector does not examine the calling assembly for attributes.
/// </para>
/// </remarks>
/// <author>Nicko Cadell</author>
public class CompactRepositorySelector : IRepositorySelector
{
#region Member Variables
private const string DefaultRepositoryName = "log4net-default-repository";
private readonly Hashtable m_name2repositoryMap = new Hashtable();
private readonly Type m_defaultRepositoryType;
private event LoggerRepositoryCreationEventHandler m_loggerRepositoryCreatedEvent;
#endregion
#region Constructors
/// <summary>
/// Create a new repository selector
/// </summary>
/// <param name="defaultRepositoryType">the type of the repositories to create, must implement <see cref="ILoggerRepository"/></param>
/// <remarks>
/// <para>
/// Create an new compact repository selector.
/// The default type for repositories must be specified,
/// an appropriate value would be <see cref="log4net.Repository.Hierarchy.Hierarchy"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException">throw if <paramref name="defaultRepositoryType"/> is null</exception>
/// <exception cref="ArgumentOutOfRangeException">throw if <paramref name="defaultRepositoryType"/> does not implement <see cref="ILoggerRepository"/></exception>
public CompactRepositorySelector(Type defaultRepositoryType)
{
if (defaultRepositoryType == null)
{
throw new ArgumentNullException("defaultRepositoryType");
}
// Check that the type is a repository
if (! (typeof(ILoggerRepository).IsAssignableFrom(defaultRepositoryType)) )
{
throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("defaultRepositoryType", (object)defaultRepositoryType, "Parameter: defaultRepositoryType, Value: ["+defaultRepositoryType+"] out of range. Argument must implement the ILoggerRepository interface");
}
m_defaultRepositoryType = defaultRepositoryType;
LogLog.Debug(declaringType, "defaultRepositoryType ["+m_defaultRepositoryType+"]");
}
#endregion
#region Implementation of IRepositorySelector
/// <summary>
/// Get the <see cref="ILoggerRepository"/> for the specified assembly
/// </summary>
/// <param name="assembly">not used</param>
/// <returns>The default <see cref="ILoggerRepository"/></returns>
/// <remarks>
/// <para>
/// The <paramref name="assembly"/> argument is not used. This selector does not create a
/// separate repository for each assembly.
/// </para>
/// <para>
/// As a named repository is not specified the default repository is
/// returned. The default repository is named <c>log4net-default-repository</c>.
/// </para>
/// </remarks>
public ILoggerRepository GetRepository(Assembly assembly)
{
return CreateRepository(assembly, m_defaultRepositoryType);
}
/// <summary>
/// Get the named <see cref="ILoggerRepository"/>
/// </summary>
/// <param name="repositoryName">the name of the repository to lookup</param>
/// <returns>The named <see cref="ILoggerRepository"/></returns>
/// <remarks>
/// <para>
/// Get the named <see cref="ILoggerRepository"/>. The default
/// repository is <c>log4net-default-repository</c>. Other repositories
/// must be created using the <see cref="M:CreateRepository(string, Type)"/>.
/// If the named repository does not exist an exception is thrown.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException">throw if <paramref name="repositoryName"/> is null</exception>
/// <exception cref="LogException">throw if the <paramref name="repositoryName"/> does not exist</exception>
public ILoggerRepository GetRepository(string repositoryName)
{
if (repositoryName == null)
{
throw new ArgumentNullException("repositoryName");
}
lock(this)
{
// Lookup in map
ILoggerRepository rep = m_name2repositoryMap[repositoryName] as ILoggerRepository;
if (rep == null)
{
throw new LogException("Repository ["+repositoryName+"] is NOT defined.");
}
return rep;
}
}
/// <summary>
/// Create a new repository for the assembly specified
/// </summary>
/// <param name="assembly">not used</param>
/// <param name="repositoryType">the type of repository to create, must implement <see cref="ILoggerRepository"/></param>
/// <returns>the repository created</returns>
/// <remarks>
/// <para>
/// The <paramref name="assembly"/> argument is not used. This selector does not create a
/// separate repository for each assembly.
/// </para>
/// <para>
/// If the <paramref name="repositoryType"/> is <c>null</c> then the
/// default repository type specified to the constructor is used.
/// </para>
/// <para>
/// As a named repository is not specified the default repository is
/// returned. The default repository is named <c>log4net-default-repository</c>.
/// </para>
/// </remarks>
public ILoggerRepository CreateRepository(Assembly assembly, Type repositoryType)
{
// If the type is not set then use the default type
if (repositoryType == null)
{
repositoryType = m_defaultRepositoryType;
}
lock(this)
{
// This method should not throw if the default repository already exists.
// First check that the repository does not exist
ILoggerRepository rep = m_name2repositoryMap[DefaultRepositoryName] as ILoggerRepository;
if (rep == null)
{
// Must create the repository
rep = CreateRepository(DefaultRepositoryName, repositoryType);
}
return rep;
}
}
/// <summary>
/// Create a new repository for the repository specified
/// </summary>
/// <param name="repositoryName">the repository to associate with the <see cref="ILoggerRepository"/></param>
/// <param name="repositoryType">the type of repository to create, must implement <see cref="ILoggerRepository"/>.
/// If this param is null then the default repository type is used.</param>
/// <returns>the repository created</returns>
/// <remarks>
/// <para>
/// The <see cref="ILoggerRepository"/> created will be associated with the repository
/// specified such that a call to <see cref="M:GetRepository(string)"/> with the
/// same repository specified will return the same repository instance.
/// </para>
/// <para>
/// If the named repository already exists an exception will be thrown.
/// </para>
/// <para>
/// If <paramref name="repositoryType"/> is <c>null</c> then the default
/// repository type specified to the constructor is used.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException">throw if <paramref name="repositoryName"/> is null</exception>
/// <exception cref="LogException">throw if the <paramref name="repositoryName"/> already exists</exception>
public ILoggerRepository CreateRepository(string repositoryName, Type repositoryType)
{
if (repositoryName == null)
{
throw new ArgumentNullException("repositoryName");
}
// If the type is not set then use the default type
if (repositoryType == null)
{
repositoryType = m_defaultRepositoryType;
}
lock(this)
{
ILoggerRepository rep = null;
// First check that the repository does not exist
rep = m_name2repositoryMap[repositoryName] as ILoggerRepository;
if (rep != null)
{
throw new LogException("Repository ["+repositoryName+"] is already defined. Repositories cannot be redefined.");
}
else
{
LogLog.Debug(declaringType, "Creating repository ["+repositoryName+"] using type ["+repositoryType+"]");
// Call the no arg constructor for the repositoryType
rep = (ILoggerRepository)Activator.CreateInstance(repositoryType);
// Set the name of the repository
rep.Name = repositoryName;
// Store in map
m_name2repositoryMap[repositoryName] = rep;
// Notify listeners that the repository has been created
OnLoggerRepositoryCreatedEvent(rep);
}
return rep;
}
}
/// <summary>
/// Test if a named repository exists
/// </summary>
/// <param name="repositoryName">the named repository to check</param>
/// <returns><c>true</c> if the repository exists</returns>
/// <remarks>
/// <para>
/// Test if a named repository exists. Use <see cref="M:CreateRepository(string, Type)"/>
/// to create a new repository and <see cref="M:GetRepository(string)"/> to retrieve
/// a repository.
/// </para>
/// </remarks>
public bool ExistsRepository(string repositoryName)
{
lock(this)
{
return m_name2repositoryMap.ContainsKey(repositoryName);
}
}
/// <summary>
/// Gets a list of <see cref="ILoggerRepository"/> objects
/// </summary>
/// <returns>an array of all known <see cref="ILoggerRepository"/> objects</returns>
/// <remarks>
/// <para>
/// Gets an array of all of the repositories created by this selector.
/// </para>
/// </remarks>
public ILoggerRepository[] GetAllRepositories()
{
lock(this)
{
ICollection reps = m_name2repositoryMap.Values;
ILoggerRepository[] all = new ILoggerRepository[reps.Count];
reps.CopyTo(all, 0);
return all;
}
}
#endregion
#region Private Static Fields
/// <summary>
/// The fully qualified type of the CompactRepositorySelector class.
/// </summary>
/// <remarks>
/// Used by the internal logger to record the Type of the
/// log message.
/// </remarks>
private readonly static Type declaringType = typeof(CompactRepositorySelector);
#endregion Private Static Fields
/// <summary>
/// Event to notify that a logger repository has been created.
/// </summary>
/// <value>
/// Event to notify that a logger repository has been created.
/// </value>
/// <remarks>
/// <para>
/// Event raised when a new repository is created.
/// The event source will be this selector. The event args will
/// be a <see cref="LoggerRepositoryCreationEventArgs"/> which
/// holds the newly created <see cref="ILoggerRepository"/>.
/// </para>
/// </remarks>
public event LoggerRepositoryCreationEventHandler LoggerRepositoryCreatedEvent
{
add { m_loggerRepositoryCreatedEvent += value; }
remove { m_loggerRepositoryCreatedEvent -= value; }
}
/// <summary>
/// Notify the registered listeners that the repository has been created
/// </summary>
/// <param name="repository">The repository that has been created</param>
/// <remarks>
/// <para>
/// Raises the <event cref="LoggerRepositoryCreatedEvent">LoggerRepositoryCreatedEvent</event>
/// event.
/// </para>
/// </remarks>
protected virtual void OnLoggerRepositoryCreatedEvent(ILoggerRepository repository)
{
LoggerRepositoryCreationEventHandler handler = m_loggerRepositoryCreatedEvent;
if (handler != null)
{
handler(this, new LoggerRepositoryCreationEventArgs(repository));
}
}
}
}