View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j.or;
    19
    20  import org.apache.log4j.spi.RendererSupport;
    21  import org.apache.log4j.helpers.LogLog;
    22  import org.apache.log4j.helpers.Loader;
    23  import org.apache.log4j.helpers.OptionConverter;
    24  import java.util.Hashtable;
    25
    26  /**
    27     Map class objects to an {@link ObjectRenderer}.
    28
    29     @author Ceki G&uuml;lc&uuml;
    30     @since version 1.0 */
    31  public class RendererMap {
    32
    33    Hashtable map;
    34
    35    static ObjectRenderer defaultRenderer = new DefaultRenderer();
    36
    37    public
    38    RendererMap() {
    39      map = new Hashtable();
    40    }
    41
    42    /**
    43       Add a renderer to a hierarchy passed as parameter.
    44    */
    45    static
    46    public
    47    void addRenderer(RendererSupport repository, String renderedClassName,
    48  		   String renderingClassName) {
    49      LogLog.debug("Rendering class: ["+renderingClassName+"], Rendered class: ["+
    50  		 renderedClassName+"].");
    51      ObjectRenderer renderer = (ObjectRenderer)
    52               OptionConverter.instantiateByClassName(renderingClassName,
    53  						    ObjectRenderer.class,
    54  						    null);
    55      if(renderer == null) {
    56        LogLog.error("Could not instantiate renderer ["+renderingClassName+"].");
    57        return;
    58      } else {
    59        try {
    60  	Class renderedClass = Loader.loadClass(renderedClassName);
    61  	repository.setRenderer(renderedClass, renderer);
    62        } catch(ClassNotFoundException e) {
    63  	LogLog.error("Could not find class ["+renderedClassName+"].", e);
    64        }
    65      }
    66    }
    67
    68
    69    /**
    70       Find the appropriate renderer for the class type of the
    71       <code>o</code> parameter. This is accomplished by calling the
    72       {@link #get(Class)} method. Once a renderer is found, it is
    73       applied on the object <code>o</code> and the result is returned
    74       as a {@link String}. */
    75    public
    76    String findAndRender(Object o) {
    77      if(o == null)
    78        return null;
    79      else
    80        return get(o.getClass()).doRender(o);
    81    }
    82
    83
    84    /**
    85       Syntactic sugar method that calls {@link #get(Class)} with the
    86       class of the object parameter. */
    87    public
    88    ObjectRenderer get(Object o) {
    89      if(o == null)
    90        return null;
    91      else
    92        return get(o.getClass());
    93    }
    94
    95
    96    /**
    97       Search the parents of <code>clazz</code> for a renderer. The
    98       renderer closest in the hierarchy will be returned. If no
    99       renderers could be found, then the default renderer is returned.
    100
    101      <p>The search first looks for a renderer configured for
    102      <code>clazz</code>. If a renderer could not be found, then the
    103      search continues by looking at all the interfaces implemented by
    104      <code>clazz</code> including the super-interfaces of each
    105      interface.  If a renderer cannot be found, then the search looks
    106      for a renderer defined for the parent (superclass) of
    107      <code>clazz</code>. If that fails, then all the interfaces
    108      implemented by the parent of <code>clazz</code> are searched and
    109      so on.
    110
    111      <p>For example, if A0, A1, A2 are classes and X0, X1, X2, Y0, Y1
    112      are interfaces where A2 extends A1 which in turn extends A0 and
    113      similarly X2 extends X1 which extends X0 and Y1 extends Y0. Let
    114      us also assume that A1 implements the Y0 interface and that A2
    115      implements the X2 interface.
    116
    117      <p>The table below shows the results returned by the
    118      <code>get(A2.class)</code> method depending on the renderers
    119      added to the map.
    120
    121      <p><table border="1">
    122      <tr><th>Added renderers</th><th>Value returned by <code>get(A2.class)</code></th>
    123
    124      <tr><td><code>A0Renderer</code>
    125          <td align="center"><code>A0Renderer</code>
    126
    127      <tr><td><code>A0Renderer, A1Renderer</code>
    128          <td align="center"><code>A1Renderer</code>
    129
    130      <tr><td><code>X0Renderer</code>
    131          <td align="center"><code>X0Renderer</code>
    132
    133      <tr><td><code>A1Renderer, X0Renderer</code>
    134          <td align="center"><code>X0Renderer</code>
    135
    136      </table>
    137
    138      <p>This search algorithm is not the most natural, although it is
    139      particularly easy to implement. Future log4j versions
    140      <em>may</em> implement a more intuitive search
    141      algorithm. However, the present algorithm should be acceptable in
    142      the vast majority of circumstances.
    143
    144  */
    145   public
    146   ObjectRenderer get(Class clazz) {
    147     //System.out.println("\nget: "+clazz);
    148     ObjectRenderer r = null;
    149     for(Class c = clazz; c != null; c = c.getSuperclass()) {
    150       //System.out.println("Searching for class: "+c);
    151       r = (ObjectRenderer) map.get(c);
    152       if(r != null) {
    153 	return r;
    154       }
    155       r = searchInterfaces(c);
    156       if(r != null)
    157 	return r;
    158     }
    159     return defaultRenderer;
    160   }
    161
    162   ObjectRenderer searchInterfaces(Class c) {
    163     //System.out.println("Searching interfaces of class: "+c);
    164
    165     ObjectRenderer r = (ObjectRenderer) map.get(c);
    166     if(r != null) {
    167       return r;
    168     } else {
    169       Class[] ia = c.getInterfaces();
    170       for(int i = 0; i < ia.length; i++) {
    171 	r = searchInterfaces(ia[i]);
    172 	if(r != null)
    173 	  return r;
    174       }
    175     }
    176     return null;
    177   }
    178
    179
    180   public
    181   ObjectRenderer getDefaultRenderer() {
    182     return defaultRenderer;
    183   }
    184
    185
    186   public
    187   void clear() {
    188     map.clear();
    189   }
    190
    191   /**
    192      Register an {@link ObjectRenderer} for <code>clazz</code>.
    193   */
    194   public
    195   void put(Class clazz, ObjectRenderer or) {
    196     map.put(clazz, or);
    197   }
    198 }