6b3483e8a755554ac6ffc51b97dc9311e336ffcc
[jalview.git] / srcjar / org / apache / log4j / or / RendererMap.java
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ülcü
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   /**
86      Syntactic sugar method that calls {@link #get(Class)} with the
87      class of the object parameter. */
88   public
89   ObjectRenderer get(Object o) {
90     if(o == null) {
91         return null;
92     } else {
93         return get(o.getClass());
94     }
95   }
96
97
98   /**
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.
102
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
111      so on.
112
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.
118
119      <p>The table below shows the results returned by the
120      <code>get(A2.class)</code> method depending on the renderers
121      added to the map.
122
123      <p><table border="1">
124      <tr><th>Added renderers</th><th>Value returned by <code>get(A2.class)</code></th>
125
126      <tr><td><code>A0Renderer</code>
127          <td align="center"><code>A0Renderer</code>
128
129      <tr><td><code>A0Renderer, A1Renderer</code>
130          <td align="center"><code>A1Renderer</code>
131
132      <tr><td><code>X0Renderer</code>
133          <td align="center"><code>X0Renderer</code>
134
135      <tr><td><code>A1Renderer, X0Renderer</code>
136          <td align="center"><code>X0Renderer</code>
137
138      </table>
139
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.
145
146  */
147   public
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);
154       if(r != null) {
155         return r;
156       }
157       r = searchInterfaces(c);
158       if(r != null) {
159         return r;
160     }
161     }
162     return defaultRenderer;
163   }
164
165   ObjectRenderer searchInterfaces(Class c) {
166     //System.out.println("Searching interfaces of class: "+c);
167
168     ObjectRenderer r = (ObjectRenderer) map.get(c);
169     if(r != null) {
170       return r;
171     } else {
172       Class[] ia = c.getInterfaces();
173       for(int i = 0; i < ia.length; i++) {
174         r = searchInterfaces(ia[i]);
175         if(r != null) {
176         return r;
177     }
178       }
179     }
180     return null;
181   }
182
183
184   public
185   ObjectRenderer getDefaultRenderer() {
186     return defaultRenderer;
187   }
188
189
190   public
191   void clear() {
192     map.clear();
193   }
194
195   /**
196      Register an {@link ObjectRenderer} for <code>clazz</code>.
197   */
198   public
199   void put(Class clazz, ObjectRenderer or) {
200     map.put(clazz, or);
201   }
202 }