#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.IO; using log4net.Util; namespace log4net.ObjectRenderer { /// /// Map class objects to an . /// /// /// /// Maintains a mapping between types that require special /// rendering and the that /// is used to render them. /// /// /// The method is used to render an /// object using the appropriate renderers defined in this map. /// /// /// Nicko Cadell /// Gert Driesen public class RendererMap { private readonly static Type declaringType = typeof(RendererMap); #region Member Variables private System.Collections.Hashtable m_map; private System.Collections.Hashtable m_cache = new System.Collections.Hashtable(); private static IObjectRenderer s_defaultRenderer = new DefaultRenderer(); #endregion #region Constructors /// /// Default Constructor /// /// /// /// Default constructor. /// /// public RendererMap() { m_map = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); } #endregion /// /// Render using the appropriate renderer. /// /// the object to render to a string /// the object rendered as a string /// /// /// This is a convenience method used to render an object to a string. /// The alternative method /// should be used when streaming output to a . /// /// public string FindAndRender(object obj) { // Optimisation for strings string strData = obj as String; if (strData != null) { return strData; } StringWriter stringWriter = new StringWriter(System.Globalization.CultureInfo.InvariantCulture); FindAndRender(obj, stringWriter); return stringWriter.ToString(); } /// /// Render using the appropriate renderer. /// /// the object to render to a string /// The writer to render to /// /// /// Find the appropriate renderer for the type of the /// parameter. This is accomplished by calling the /// method. Once a renderer is found, it is /// applied on the object and the result is returned /// as a . /// /// public void FindAndRender(object obj, TextWriter writer) { if (obj == null) { writer.Write(SystemInfo.NullText); } else { // Optimisation for strings string str = obj as string; if (str != null) { writer.Write(str); } else { // Lookup the renderer for the specific type try { Get(obj.GetType()).RenderObject(this, obj, writer); } catch(Exception ex) { // Exception rendering the object log4net.Util.LogLog.Error(declaringType, "Exception while rendering object of type ["+obj.GetType().FullName+"]", ex); // return default message string objectTypeName = ""; if (obj != null && obj.GetType() != null) { objectTypeName = obj.GetType().FullName; } writer.Write("Exception rendering object type ["+objectTypeName+"]"); if (ex != null) { string exceptionText = null; try { exceptionText = ex.ToString(); } catch { // Ignore exception } writer.Write("" + exceptionText + ""); } writer.Write(""); } } } } /// /// Gets the renderer for the specified object type /// /// the object to lookup the renderer for /// the renderer for /// /// /// Gets the renderer for the specified object type. /// /// /// Syntactic sugar method that calls /// with the type of the object parameter. /// /// public IObjectRenderer Get(Object obj) { if (obj == null) { return null; } else { return Get(obj.GetType()); } } /// /// Gets the renderer for the specified type /// /// the type to lookup the renderer for /// the renderer for the specified type /// /// /// Returns the renderer for the specified type. /// If no specific renderer has been defined the /// will be returned. /// /// public IObjectRenderer Get(Type type) { if (type == null) { throw new ArgumentNullException("type"); } IObjectRenderer result = null; // Check cache result = (IObjectRenderer)m_cache[type]; if (result == null) { for(Type cur = type; cur != null; cur = cur.BaseType) { // Search the type's interfaces result = SearchTypeAndInterfaces(cur); if (result != null) { break; } } // if not set then use the default renderer if (result == null) { result = s_defaultRenderer; } // Add to cache m_cache[type] = result; } return result; } /// /// Internal function to recursively search interfaces /// /// the type to lookup the renderer for /// the renderer for the specified type private IObjectRenderer SearchTypeAndInterfaces(Type type) { IObjectRenderer r = (IObjectRenderer)m_map[type]; if (r != null) { return r; } else { foreach(Type t in type.GetInterfaces()) { r = SearchTypeAndInterfaces(t); if (r != null) { return r; } } } return null; } /// /// Get the default renderer instance /// /// the default renderer /// /// /// Get the default renderer /// /// public IObjectRenderer DefaultRenderer { get { return s_defaultRenderer; } } /// /// Clear the map of renderers /// /// /// /// Clear the custom renderers defined by using /// . The /// cannot be removed. /// /// public void Clear() { m_map.Clear(); m_cache.Clear(); } /// /// Register an for . /// /// the type that will be rendered by /// the renderer for /// /// /// Register an object renderer for a specific source type. /// This renderer will be returned from a call to /// specifying the same as an argument. /// /// public void Put(Type typeToRender, IObjectRenderer renderer) { m_cache.Clear(); if (typeToRender == null) { throw new ArgumentNullException("typeToRender"); } if (renderer == null) { throw new ArgumentNullException("renderer"); } m_map[typeToRender] = renderer; } } }