#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 { /// /// Implementation of Properties collection for the /// /// /// /// Class implements a collection of properties that is specific to each thread. /// The class is not synchronized as each thread has its own . /// /// /// This class stores its properties in a slot on the named /// log4net.Util.LogicalThreadContextProperties. /// /// /// The requires a link time /// for the /// . /// 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. /// /// /// Nicko Cadell public sealed class LogicalThreadContextProperties : ContextPropertiesBase { private const string c_SlotName = "log4net.Util.LogicalThreadContextProperties"; /// /// Flag used to disable this context if we don't have permission to access the CallContext. /// private bool m_disabled = false; #region Public Instance Constructors /// /// Constructor /// /// /// /// Initializes a new instance of the class. /// /// internal LogicalThreadContextProperties() { } #endregion Public Instance Constructors #region Public Instance Properties /// /// Gets or sets the value of a property /// /// /// The value for the property with the specified key /// /// /// /// Get or set the property value for the specified. /// /// 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 /// /// Remove a property /// /// the key for the entry to remove /// /// /// Remove the value for the specified from the context. /// /// public void Remove(string key) { PropertiesDictionary dictionary = GetProperties(false); if (dictionary != null) { dictionary.Remove(key); } } /// /// Clear all the context properties /// /// /// /// Clear all the context properties /// /// public void Clear() { PropertiesDictionary dictionary = GetProperties(false); if (dictionary != null) { dictionary.Clear(); } } #endregion Public Instance Methods #region Internal Instance Methods /// /// Get the PropertiesDictionary stored in the LocalDataStoreSlot for this thread. /// /// create the dictionary if it does not exist, otherwise return null if is does not exist /// the properties for this thread /// /// /// 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. /// /// 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 /// /// Gets the call context get data. /// /// The peroperties dictionary stored in the call context /// /// The method has a /// security link demand, therfore we must put the method call in a seperate method /// that we can wrap in an exception handler. /// #if NET_4_0 [System.Security.SecuritySafeCritical] #endif private static PropertiesDictionary GetCallContextData() { #if NET_2_0 || MONO_2_0 return CallContext.LogicalGetData(c_SlotName) as PropertiesDictionary; #else return CallContext.GetData(c_SlotName) as PropertiesDictionary; #endif } /// /// Sets the call context data. /// /// The properties. /// /// The method has a /// security link demand, therfore we must put the method call in a seperate method /// that we can wrap in an exception handler. /// #if NET_4_0 [System.Security.SecuritySafeCritical] #endif private static void SetCallContextData(PropertiesDictionary properties) { #if NET_2_0 || MONO_2_0 CallContext.LogicalSetData(c_SlotName, properties); #else CallContext.SetData(c_SlotName, properties); #endif } #endregion #region Private Static Fields /// /// The fully qualified type of the LogicalThreadContextProperties class. /// /// /// Used by the internal logger to record the Type of the /// log message. /// private readonly static Type declaringType = typeof(LogicalThreadContextProperties); #endregion Private Static Fields } } #endif