#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; #if !NETCF_1_0 using System.Collections; #endif using log4net.Core; namespace log4net.Util { /// /// Implementation of Stack for the /// /// /// /// Implementation of Stack for the /// /// /// Nicko Cadell public sealed class ThreadContextStack : IFixingRequired { #region Private Static Fields /// /// The stack store. /// private Stack m_stack = new Stack(); #endregion Private Static Fields #region Public Instance Constructors /// /// Internal constructor /// /// /// /// Initializes a new instance of the class. /// /// internal ThreadContextStack() { } #endregion Public Instance Constructors #region Public Properties /// /// The number of messages in the stack /// /// /// The current number of messages in the stack /// /// /// /// The current number of messages in the stack. That is /// the number of times has been called /// minus the number of times has been called. /// /// public int Count { get { return m_stack.Count; } } #endregion // Public Properties #region Public Methods /// /// Clears all the contextual information held in this stack. /// /// /// /// Clears all the contextual information held in this stack. /// Only call this if you think that this tread is being reused after /// a previous call execution which may not have completed correctly. /// You do not need to use this method if you always guarantee to call /// the method of the /// returned from even in exceptional circumstances, /// for example by using the using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message")) /// syntax. /// /// public void Clear() { m_stack.Clear(); } /// /// Removes the top context from this stack. /// /// The message in the context that was removed from the top of this stack. /// /// /// Remove the top context from this stack, and return /// it to the caller. If this stack is empty then an /// empty string (not ) is returned. /// /// public string Pop() { Stack stack = m_stack; if (stack.Count > 0) { return ((StackFrame)(stack.Pop())).Message; } return ""; } /// /// Pushes a new context message into this stack. /// /// The new context message. /// /// An that can be used to clean up the context stack. /// /// /// /// Pushes a new context onto this stack. An /// is returned that can be used to clean up this stack. This /// can be easily combined with the using keyword to scope the /// context. /// /// /// Simple example of using the Push method with the using keyword. /// /// using(log4net.ThreadContext.Stacks["NDC"].Push("Stack_Message")) /// { /// log.Warn("This should have an ThreadContext Stack message"); /// } /// /// public IDisposable Push(string message) { Stack stack = m_stack; stack.Push(new StackFrame(message, (stack.Count>0) ? (StackFrame)stack.Peek() : null)); return new AutoPopStackFrame(stack, stack.Count - 1); } #endregion Public Methods #region Internal Methods /// /// Gets the current context information for this stack. /// /// The current context information. internal string GetFullMessage() { Stack stack = m_stack; if (stack.Count > 0) { return ((StackFrame)(stack.Peek())).FullMessage; } return null; } /// /// Gets and sets the internal stack used by this /// /// The internal storage stack /// /// /// This property is provided only to support backward compatability /// of the . Tytpically the internal stack should not /// be modified. /// /// internal Stack InternalStack { get { return m_stack; } set { m_stack = value; } } #endregion Internal Methods /// /// Gets the current context information for this stack. /// /// Gets the current context information /// /// /// Gets the current context information for this stack. /// /// public override string ToString() { return GetFullMessage(); } /// /// Get a portable version of this object /// /// the portable instance of this object /// /// /// Get a cross thread portable version of this object /// /// object IFixingRequired.GetFixedObject() { return GetFullMessage(); } /// /// Inner class used to represent a single context frame in the stack. /// /// /// /// Inner class used to represent a single context frame in the stack. /// /// private sealed class StackFrame { #region Private Instance Fields private readonly string m_message; private readonly StackFrame m_parent; private string m_fullMessage = null; #endregion #region Internal Instance Constructors /// /// Constructor /// /// The message for this context. /// The parent context in the chain. /// /// /// Initializes a new instance of the class /// with the specified message and parent context. /// /// internal StackFrame(string message, StackFrame parent) { m_message = message; m_parent = parent; if (parent == null) { m_fullMessage = message; } } #endregion Internal Instance Constructors #region Internal Instance Properties /// /// Get the message. /// /// The message. /// /// /// Get the message. /// /// internal string Message { get { return m_message; } } /// /// Gets the full text of the context down to the root level. /// /// /// The full text of the context down to the root level. /// /// /// /// Gets the full text of the context down to the root level. /// /// internal string FullMessage { get { if (m_fullMessage == null && m_parent != null) { m_fullMessage = string.Concat(m_parent.FullMessage, " ", m_message); } return m_fullMessage; } } #endregion Internal Instance Properties } /// /// Struct returned from the method. /// /// /// /// This struct implements the and is designed to be used /// with the pattern to remove the stack frame at the end of the scope. /// /// private struct AutoPopStackFrame : IDisposable { #region Private Instance Fields /// /// The ThreadContextStack internal stack /// private Stack m_frameStack; /// /// The depth to trim the stack to when this instance is disposed /// private int m_frameDepth; #endregion Private Instance Fields #region Internal Instance Constructors /// /// Constructor /// /// The internal stack used by the ThreadContextStack. /// The depth to return the stack to when this object is disposed. /// /// /// Initializes a new instance of the class with /// the specified stack and return depth. /// /// internal AutoPopStackFrame(Stack frameStack, int frameDepth) { m_frameStack = frameStack; m_frameDepth = frameDepth; } #endregion Internal Instance Constructors #region Implementation of IDisposable /// /// Returns the stack to the correct depth. /// /// /// /// Returns the stack to the correct depth. /// /// public void Dispose() { if (m_frameDepth >= 0 && m_frameStack != null) { while(m_frameStack.Count > m_frameDepth) { m_frameStack.Pop(); } } } #endregion Implementation of IDisposable } #if NETCF_1_0 /// /// Subclass of to /// provide missing methods. /// /// /// /// The Compact Framework version of the /// class is missing the Clear and Clone methods. /// This subclass adds implementations of those missing methods. /// /// public class Stack : System.Collections.Stack { /// /// Clears the stack of all elements. /// /// /// /// Clears the stack of all elements. /// /// public void Clear() { while(Count > 0) { Pop(); } } /// /// Makes a shallow copy of the stack's elements. /// /// A new stack that has a shallow copy of the stack's elements. /// /// /// Makes a shallow copy of the stack's elements. /// /// public Stack Clone() { Stack res = new Stack(); object[] items = ToArray(); foreach(object item in items) { res.Push(item); } return res; } } #endif } }