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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org.apache.log4j.or;
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;
27 Map class objects to an {@link ObjectRenderer}.
29 @author Ceki Gülcü
31 public class RendererMap {
35 static ObjectRenderer defaultRenderer = new DefaultRenderer();
39 map = new Hashtable();
43 Add a renderer to a hierarchy passed as parameter.
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,
55 if(renderer == null) {
56 LogLog.error("Could not instantiate renderer ["+renderingClassName+"].");
60 Class renderedClass = Loader.loadClass(renderedClassName);
61 repository.setRenderer(renderedClass, renderer);
62 } catch(ClassNotFoundException e) {
63 LogLog.error("Could not find class ["+renderedClassName+"].", e);
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}. */
76 String findAndRender(Object o) {
80 return get(o.getClass()).doRender(o);
86 Syntactic sugar method that calls {@link #get(Class)} with the
87 class of the object parameter. */
89 ObjectRenderer get(Object o) {
93 return get(o.getClass());
99 Search the parents of <code>clazz</code> for a renderer. The
100 renderer closest in the hierarchy will be returned. If no
101 renderers could be found, then the default renderer is returned.
103 <p>The search first looks for a renderer configured for
104 <code>clazz</code>. If a renderer could not be found, then the
105 search continues by looking at all the interfaces implemented by
106 <code>clazz</code> including the super-interfaces of each
107 interface. If a renderer cannot be found, then the search looks
108 for a renderer defined for the parent (superclass) of
109 <code>clazz</code>. If that fails, then all the interfaces
110 implemented by the parent of <code>clazz</code> are searched and
113 <p>For example, if A0, A1, A2 are classes and X0, X1, X2, Y0, Y1
114 are interfaces where A2 extends A1 which in turn extends A0 and
115 similarly X2 extends X1 which extends X0 and Y1 extends Y0. Let
116 us also assume that A1 implements the Y0 interface and that A2
117 implements the X2 interface.
119 <p>The table below shows the results returned by the
120 <code>get(A2.class)</code> method depending on the renderers
123 <p><table border="1">
124 <tr><th>Added renderers</th><th>Value returned by <code>get(A2.class)</code></th>
126 <tr><td><code>A0Renderer</code>
127 <td align="center"><code>A0Renderer</code>
129 <tr><td><code>A0Renderer, A1Renderer</code>
130 <td align="center"><code>A1Renderer</code>
132 <tr><td><code>X0Renderer</code>
133 <td align="center"><code>X0Renderer</code>
135 <tr><td><code>A1Renderer, X0Renderer</code>
136 <td align="center"><code>X0Renderer</code>
140 <p>This search algorithm is not the most natural, although it is
141 particularly easy to implement. Future log4j versions
142 <em>may</em> implement a more intuitive search
143 algorithm. However, the present algorithm should be acceptable in
144 the vast majority of circumstances.
148 ObjectRenderer get(Class clazz) {
149 //System.out.println("\nget: "+clazz);
150 ObjectRenderer r = null;
151 for(Class c = clazz; c != null; c = c.getSuperclass()) {
152 //System.out.println("Searching for class: "+c);
153 r = (ObjectRenderer) map.get(c);
157 r = searchInterfaces(c);
162 return defaultRenderer;
165 ObjectRenderer searchInterfaces(Class c) {
166 //System.out.println("Searching interfaces of class: "+c);
168 ObjectRenderer r = (ObjectRenderer) map.get(c);
172 Class[] ia = c.getInterfaces();
173 for(int i = 0; i < ia.length; i++) {
174 r = searchInterfaces(ia[i]);
185 ObjectRenderer getDefaultRenderer() {
186 return defaultRenderer;
196 Register an {@link ObjectRenderer} for <code>clazz</code>.
199 void put(Class clazz, ObjectRenderer or) {