#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
|
|
// .NET Compact Framework 1.0 has no support for System.Runtime.Remoting.Messaging.CallContext
|
#if !NETCF
|
|
using System;
|
using System.Runtime.Remoting.Messaging;
|
using System.Security;
|
|
namespace log4net.Util
|
{
|
/// <summary>
|
/// Implementation of Properties collection for the <see cref="log4net.LogicalThreadContext"/>
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Class implements a collection of properties that is specific to each thread.
|
/// The class is not synchronized as each thread has its own <see cref="PropertiesDictionary"/>.
|
/// </para>
|
/// <para>
|
/// This class stores its properties in a slot on the <see cref="CallContext"/> named
|
/// <c>log4net.Util.LogicalThreadContextProperties</c>.
|
/// </para>
|
/// <para>
|
/// The <see cref="CallContext"/> requires a link time
|
/// <see cref="System.Security.Permissions.SecurityPermission"/> for the
|
/// <see cref="System.Security.Permissions.SecurityPermissionFlag.Infrastructure"/>.
|
/// If the calling code does not have this permission then this context will be disabled.
|
/// It will not store any property values set on it.
|
/// </para>
|
/// </remarks>
|
/// <author>Nicko Cadell</author>
|
public sealed class LogicalThreadContextProperties : ContextPropertiesBase
|
{
|
private const string c_SlotName = "log4net.Util.LogicalThreadContextProperties";
|
|
/// <summary>
|
/// Flag used to disable this context if we don't have permission to access the CallContext.
|
/// </summary>
|
private bool m_disabled = false;
|
|
#region Public Instance Constructors
|
|
/// <summary>
|
/// Constructor
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Initializes a new instance of the <see cref="LogicalThreadContextProperties" /> class.
|
/// </para>
|
/// </remarks>
|
internal LogicalThreadContextProperties()
|
{
|
}
|
|
#endregion Public Instance Constructors
|
|
#region Public Instance Properties
|
|
/// <summary>
|
/// Gets or sets the value of a property
|
/// </summary>
|
/// <value>
|
/// The value for the property with the specified key
|
/// </value>
|
/// <remarks>
|
/// <para>
|
/// Get or set the property value for the <paramref name="key"/> specified.
|
/// </para>
|
/// </remarks>
|
override public object this[string key]
|
{
|
get
|
{
|
// Don't create the dictionary if it does not already exist
|
PropertiesDictionary dictionary = GetProperties(false);
|
if (dictionary != null)
|
{
|
return dictionary[key];
|
}
|
return null;
|
}
|
set
|
{
|
// Force the dictionary to be created
|
GetProperties(true)[key] = value;
|
}
|
}
|
|
#endregion Public Instance Properties
|
|
#region Public Instance Methods
|
|
/// <summary>
|
/// Remove a property
|
/// </summary>
|
/// <param name="key">the key for the entry to remove</param>
|
/// <remarks>
|
/// <para>
|
/// Remove the value for the specified <paramref name="key"/> from the context.
|
/// </para>
|
/// </remarks>
|
public void Remove(string key)
|
{
|
PropertiesDictionary dictionary = GetProperties(false);
|
if (dictionary != null)
|
{
|
dictionary.Remove(key);
|
}
|
}
|
|
/// <summary>
|
/// Clear all the context properties
|
/// </summary>
|
/// <remarks>
|
/// <para>
|
/// Clear all the context properties
|
/// </para>
|
/// </remarks>
|
public void Clear()
|
{
|
PropertiesDictionary dictionary = GetProperties(false);
|
if (dictionary != null)
|
{
|
dictionary.Clear();
|
}
|
}
|
|
#endregion Public Instance Methods
|
|
#region Internal Instance Methods
|
|
/// <summary>
|
/// Get the PropertiesDictionary stored in the LocalDataStoreSlot for this thread.
|
/// </summary>
|
/// <param name="create">create the dictionary if it does not exist, otherwise return null if is does not exist</param>
|
/// <returns>the properties for this thread</returns>
|
/// <remarks>
|
/// <para>
|
/// The collection returned is only to be used on the calling thread. If the
|
/// caller needs to share the collection between different threads then the
|
/// caller must clone the collection before doings so.
|
/// </para>
|
/// </remarks>
|
internal PropertiesDictionary GetProperties(bool create)
|
{
|
if (!m_disabled)
|
{
|
try
|
{
|
PropertiesDictionary properties = GetCallContextData();
|
if (properties == null && create)
|
{
|
properties = new PropertiesDictionary();
|
SetCallContextData(properties);
|
}
|
return properties;
|
}
|
catch (SecurityException secEx)
|
{
|
m_disabled = true;
|
|
// Thrown if we don't have permission to read or write the CallContext
|
LogLog.Warn(declaringType, "SecurityException while accessing CallContext. Disabling LogicalThreadContextProperties", secEx);
|
}
|
}
|
|
// Only get here is we are disabled because of a security exception
|
if (create)
|
{
|
return new PropertiesDictionary();
|
}
|
return null;
|
}
|
|
#endregion Internal Instance Methods
|
|
#region Private Static Methods
|
|
/// <summary>
|
/// Gets the call context get data.
|
/// </summary>
|
/// <returns>The peroperties dictionary stored in the call context</returns>
|
/// <remarks>
|
/// The <see cref="CallContext"/> method <see cref="CallContext.GetData"/> has a
|
/// security link demand, therfore we must put the method call in a seperate method
|
/// that we can wrap in an exception handler.
|
/// </remarks>
|
#if NET_4_0
|
[System.Security.SecuritySafeCritical]
|
#endif
|
private static PropertiesDictionary GetCallContextData()
|
{
|
return CallContext.GetData(c_SlotName) as PropertiesDictionary;
|
}
|
|
/// <summary>
|
/// Sets the call context data.
|
/// </summary>
|
/// <param name="properties">The properties.</param>
|
/// <remarks>
|
/// The <see cref="CallContext"/> method <see cref="CallContext.SetData"/> has a
|
/// security link demand, therfore we must put the method call in a seperate method
|
/// that we can wrap in an exception handler.
|
/// </remarks>
|
#if NET_4_0
|
[System.Security.SecuritySafeCritical]
|
#endif
|
private static void SetCallContextData(PropertiesDictionary properties)
|
{
|
CallContext.SetData(c_SlotName, properties);
|
}
|
|
#endregion
|
|
#region Private Static Fields
|
|
/// <summary>
|
/// The fully qualified type of the LogicalThreadContextProperties class.
|
/// </summary>
|
/// <remarks>
|
/// Used by the internal logger to record the Type of the
|
/// log message.
|
/// </remarks>
|
private readonly static Type declaringType = typeof(LogicalThreadContextProperties);
|
|
#endregion Private Static Fields
|
}
|
}
|
|
#endif
|