123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- #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;
- #if NETSTANDARD1_3
- using System.Reflection;
- #endif
- using log4net.Util;
- namespace log4net.ObjectRenderer
- {
- /// <summary>
- /// Map class objects to an <see cref="IObjectRenderer"/>.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Maintains a mapping between types that require special
- /// rendering and the <see cref="IObjectRenderer"/> that
- /// is used to render them.
- /// </para>
- /// <para>
- /// The <see cref="M:FindAndRender(object)"/> method is used to render an
- /// <c>object</c> using the appropriate renderers defined in this map.
- /// </para>
- /// </remarks>
- /// <author>Nicko Cadell</author>
- /// <author>Gert Driesen</author>
- 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
- /// <summary>
- /// Default Constructor
- /// </summary>
- /// <remarks>
- /// <para>
- /// Default constructor.
- /// </para>
- /// </remarks>
- public RendererMap()
- {
- m_map = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable());
- }
- #endregion
- /// <summary>
- /// Render <paramref name="obj"/> using the appropriate renderer.
- /// </summary>
- /// <param name="obj">the object to render to a string</param>
- /// <returns>the object rendered as a string</returns>
- /// <remarks>
- /// <para>
- /// This is a convenience method used to render an object to a string.
- /// The alternative method <see cref="M:FindAndRender(object,TextWriter)"/>
- /// should be used when streaming output to a <see cref="TextWriter"/>.
- /// </para>
- /// </remarks>
- 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();
- }
- /// <summary>
- /// Render <paramref name="obj"/> using the appropriate renderer.
- /// </summary>
- /// <param name="obj">the object to render to a string</param>
- /// <param name="writer">The writer to render to</param>
- /// <remarks>
- /// <para>
- /// Find the appropriate renderer for the type of the
- /// <paramref name="obj"/> parameter. This is accomplished by calling the
- /// <see cref="M:Get(Type)"/> method. Once a renderer is found, it is
- /// applied on the object <paramref name="obj"/> and the result is returned
- /// as a <see cref="string"/>.
- /// </para>
- /// </remarks>
- 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("<log4net.Error>Exception rendering object type ["+objectTypeName+"]");
- if (ex != null)
- {
- string exceptionText = null;
- try
- {
- exceptionText = ex.ToString();
- }
- catch
- {
- // Ignore exception
- }
- writer.Write("<stackTrace>" + exceptionText + "</stackTrace>");
- }
- writer.Write("</log4net.Error>");
- }
- }
- }
- }
- /// <summary>
- /// Gets the renderer for the specified object type
- /// </summary>
- /// <param name="obj">the object to lookup the renderer for</param>
- /// <returns>the renderer for <paramref name="obj"/></returns>
- /// <remarks>
- /// <param>
- /// Gets the renderer for the specified object type.
- /// </param>
- /// <param>
- /// Syntactic sugar method that calls <see cref="M:Get(Type)"/>
- /// with the type of the object parameter.
- /// </param>
- /// </remarks>
- public IObjectRenderer Get(Object obj)
- {
- if (obj == null)
- {
- return null;
- }
- else
- {
- return Get(obj.GetType());
- }
- }
-
- /// <summary>
- /// Gets the renderer for the specified type
- /// </summary>
- /// <param name="type">the type to lookup the renderer for</param>
- /// <returns>the renderer for the specified type</returns>
- /// <remarks>
- /// <para>
- /// Returns the renderer for the specified type.
- /// If no specific renderer has been defined the
- /// <see cref="DefaultRenderer"/> will be returned.
- /// </para>
- /// </remarks>
- 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)
- {
- #if NETSTANDARD1_3
- for (Type cur = type; cur != null; cur = cur.GetTypeInfo().BaseType)
- #else
- for(Type cur = type; cur != null; cur = cur.BaseType)
- #endif
- {
- // 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;
- }
- /// <summary>
- /// Internal function to recursively search interfaces
- /// </summary>
- /// <param name="type">the type to lookup the renderer for</param>
- /// <returns>the renderer for the specified type</returns>
- 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;
- }
- /// <summary>
- /// Get the default renderer instance
- /// </summary>
- /// <value>the default renderer</value>
- /// <remarks>
- /// <para>
- /// Get the default renderer
- /// </para>
- /// </remarks>
- public IObjectRenderer DefaultRenderer
- {
- get { return s_defaultRenderer; }
- }
- /// <summary>
- /// Clear the map of renderers
- /// </summary>
- /// <remarks>
- /// <para>
- /// Clear the custom renderers defined by using
- /// <see cref="Put"/>. The <see cref="DefaultRenderer"/>
- /// cannot be removed.
- /// </para>
- /// </remarks>
- public void Clear()
- {
- m_map.Clear();
- m_cache.Clear();
- }
- /// <summary>
- /// Register an <see cref="IObjectRenderer"/> for <paramref name="typeToRender"/>.
- /// </summary>
- /// <param name="typeToRender">the type that will be rendered by <paramref name="renderer"/></param>
- /// <param name="renderer">the renderer for <paramref name="typeToRender"/></param>
- /// <remarks>
- /// <para>
- /// Register an object renderer for a specific source type.
- /// This renderer will be returned from a call to <see cref="M:Get(Type)"/>
- /// specifying the same <paramref name="typeToRender"/> as an argument.
- /// </para>
- /// </remarks>
- 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;
- }
- }
- }
|