Clover coverage report - brownies library - 1.0-beta-1 Coverage timestamp: 月 8 16 2004 17:14:42 GMT+09:00 FRAMES NO FRAMES |
file stats: | LOC: | 703 |  | Methods: | 18
| NCLOC: | 276 |  | Classes: | 2
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
Source file | Conditionals | Statements | Methods | TOTAL
PropertyConfigurator.java | 0% | 0% | 0% | 0% |

1 |  |
     /*
2 |  |
      * Joey and its relative products are published under the terms
3 |  |
      * of the Apache Software License.
4 |  |
      */
5 |  |
     /*
6 |  |
      * Created on 2003/12/27
7 |  |
      */
8 |  |
     package org.asyrinx.brownie.log.log4j;
9 |  |
10 |  |
     import java.io.FileInputStream;
11 |  |
     import java.io.IOException;
12 |  |
     import java.util.Enumeration;
13 |  |
     import java.util.Hashtable;
14 |  |
     import java.util.Properties;
15 |  |
     import java.util.StringTokenizer;
16 |  |
17 |  |
     import org.apache.log4j.Appender;
18 |  |
     import org.apache.log4j.Layout;
19 |  |
     import org.apache.log4j.Level;
20 |  |
     import org.apache.log4j.LogManager;
21 |  |
     import org.apache.log4j.Logger;
22 |  |
     import org.apache.log4j.PatternLayout;
23 |  |
     import org.apache.log4j.config.PropertySetter;
24 |  |
     import org.apache.log4j.helpers.FileWatchdog;
25 |  |
     import org.apache.log4j.helpers.LogLog;
26 |  |
     import org.apache.log4j.helpers.OptionConverter;
27 |  |
     import org.apache.log4j.or.RendererMap;
28 |  |
     import org.apache.log4j.spi.Configurator;
29 |  |
     import org.apache.log4j.spi.LoggerFactory;
30 |  |
     import org.apache.log4j.spi.LoggerRepository;
31 |  |
     import org.apache.log4j.spi.OptionHandler;
32 |  |
     import org.apache.log4j.spi.RendererSupport;
33 |  |
34 |  |
     /**
35 |  |
      * @author akima
36 |  |
      */
37 |  |
     public class PropertyConfigurator implements Configurator {
38 |  |
39 |  |
         /**
40 |  |
          * Used internally to keep track of configured appenders.
41 |  |
          */
42 |  |
         protected Hashtable registry = new Hashtable(11);
43 |  |
44 |  |
         protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
45 |  |
46 |  |
         protected static final String CATEGORY_PREFIX = "log4j.category.";
47 |  |
48 |  |
         protected static final String LOGGER_PREFIX = "log4j.logger.";
49 |  |
50 |  |
         protected static final String FACTORY_PREFIX = "log4j.factory";
51 |  |
52 |  |
         protected static final String ADDITIVITY_PREFIX = "log4j.additivity.";
53 |  |
54 |  |
         protected static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
55 |  |
56 |  |
         protected static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
57 |  |
58 |  |
         protected static final String APPENDER_PREFIX = "log4j.appender.";
59 |  |
60 |  |
         protected static final String RENDERER_PREFIX = "log4j.renderer.";
61 |  |
62 |  |
         protected static final String THRESHOLD_PREFIX = "log4j.threshold";
63 |  |
64 |  |
         /**
65 |  |
          * Key for specifying the {@link org.apache.log4j.spi.LoggerFactory
66 |  |
          * LoggerFactory}. Currently set to "<code>log4j.loggerFactory</code>".
67 |  |
          */
68 |  |
         public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
69 |  |
70 |  |
         static final private String INTERNAL_ROOT_NAME = "root";
71 |  |
72 |  |
         /**
73 |  |
          * Read configuration from a file. <b>The existing configuration is not
74 |  |
          * cleared nor reset. </b> If you require a different behavior, then call
75 |  |
          * {@link  LogManager#resetConfigurationresetConfiguration}method before
76 |  |
          * calling <code>doConfigure</code>.
77 |  |
          *
78 |  |
          * <p>
79 |  |
          * The configuration file consists of statements in the format
80 |  |
          * <code>key=value</code>. The syntax of different configuration elements
81 |  |
          * are discussed below.
82 |  |
          *
83 |  |
          * <h3>Repository-wide threshold</h3>
84 |  |
          *
85 |  |
          * <p>
86 |  |
          * The repository-wide threshold filters logging requests by level
87 |  |
          * regardless of logger. The syntax is:
88 |  |
          *
89 |  |
          * <pre>
90 |  |
          *
91 |  |
          *
92 |  |
          *
93 |  |
          *        log4j.threshold=[level]
94 |  |
          *
95 |  |
          *
96 |  |
          *
97 |  |
          * </pre>
98 |  |
          *
99 |  |
          * <p>
100 |  |
          * The level value can consist of the string values OFF, FATAL, ERROR, WARN,
101 |  |
          * INFO, DEBUG, ALL or a <em>custom level</em> value. A custom level value
102 |  |
          * can be specified in the form level#classname. By default the
103 |  |
          * repository-wide threshold is set to the lowest possible value, namely the
104 |  |
          * level <code>ALL</code>.
105 |  |
          * </p>
106 |  |
          *
107 |  |
          *
108 |  |
          * <h3>Appender configuration</h3>
109 |  |
          *
110 |  |
          * <p>
111 |  |
          * Appender configuration syntax is:
112 |  |
          *
113 |  |
          * <pre>
114 |  |
          *
115 |  |
          *
116 |  |
          *
117 |  |
          *        # For appender named &lt;i&gt;appenderName&lt;/i&gt;, set its class.
118 |  |
          *        # Note: The appender name can contain dots.
119 |  |
          *        log4j.appender.appenderName=fully.qualified.name.of.appender.class
120 |  |
          *
121 |  |
          *        # Set appender specific options.
122 |  |
          *        log4j.appender.appenderName.option1=value1
123 |  |
          *        ...
124 |  |
          *        log4j.appender.appenderName.optionN=valueN
125 |  |
          *
126 |  |
          *
127 |  |
          *
128 |  |
          * </pre>
129 |  |
          *
130 |  |
          * For each named appender you can configure its {@link Layout}. The syntax
131 |  |
          * for configuring an appender's layout is:
132 |  |
          *
133 |  |
          * <pre>
134 |  |
          *
135 |  |
          *
136 |  |
          *
137 |  |
          *        log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
138 |  |
          *        log4j.appender.appenderName.layout.option1=value1
139 |  |
          *        ....
140 |  |
          *        log4j.appender.appenderName.layout.optionN=valueN
141 |  |
          *
142 |  |
          *
143 |  |
          *
144 |  |
          * </pre>
145 |  |
          *
146 |  |
          * <h3>Configuring loggers</h3>
147 |  |
          *
148 |  |
          * <p>
149 |  |
          * The syntax for configuring the root logger is:
150 |  |
          *
151 |  |
          * <pre>
152 |  |
          *
153 |  |
          *
154 |  |
          *
155 |  |
          *        log4j.rootLogger=[level], appenderName, appenderName, ...
156 |  |
          *
157 |  |
          *
158 |  |
          *
159 |  |
          * </pre>
160 |  |
          *
161 |  |
          * <p>
162 |  |
          * This syntax means that an optional <em>level</em> can be supplied
163 |  |
          * followed by appender names separated by commas.
164 |  |
          *
165 |  |
          * <p>
166 |  |
          * The level value can consist of the string values OFF, FATAL, ERROR, WARN,
167 |  |
          * INFO, DEBUG, ALL or a <em>custom level</em> value. A custom level value
168 |  |
          * can be specified in the form <code>level#classname</code>.
169 |  |
          *
170 |  |
          * <p>
171 |  |
          * If a level value is specified, then the root level is set to the
172 |  |
          * corresponding level. If no level value is specified, then the root level
173 |  |
          * remains untouched.
174 |  |
          *
175 |  |
          * <p>
176 |  |
          * The root logger can be assigned multiple appenders.
177 |  |
          *
178 |  |
          * <p>
179 |  |
          * Each <i>appenderName </i> (separated by commas) will be added to the root
180 |  |
          * logger. The named appender is defined using the appender syntax defined
181 |  |
          * above.
182 |  |
          *
183 |  |
          * <p>
184 |  |
          * For non-root categories the syntax is almost the same:
185 |  |
          *
186 |  |
          * <pre>
187 |  |
          *
188 |  |
          *
189 |  |
          *
190 |  |
          *        log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
191 |  |
          *
192 |  |
          *
193 |  |
          *
194 |  |
          * </pre>
195 |  |
          *
196 |  |
          * <p>
197 |  |
          * The meaning of the optional level value is discussed above in relation to
198 |  |
          * the root logger. In addition however, the value INHERITED can be
199 |  |
          * specified meaning that the named logger should inherit its level from the
200 |  |
          * logger hierarchy.
201 |  |
          *
202 |  |
          * <p>
203 |  |
          * If no level value is supplied, then the level of the named logger remains
204 |  |
          * untouched.
205 |  |
          *
206 |  |
          * <p>
207 |  |
          * By default categories inherit their level from the hierarchy. However, if
208 |  |
          * you set the level of a logger and later decide that that logger should
209 |  |
          * inherit its level, then you should specify INHERITED as the value for the
210 |  |
          * level value. NULL is a synonym for INHERITED.
211 |  |
          *
212 |  |
          * <p>
213 |  |
          * Similar to the root logger syntax, each <i>appenderName </i> (separated
214 |  |
          * by commas) will be attached to the named logger.
215 |  |
          *
216 |  |
          * <p>
217 |  |
          * See the <a href="../../../../manual.html#additivity">appender additivity
218 |  |
          * rule </a> in the user manual for the meaning of the
219 |  |
          * <code>additivity</code> flag.
220 |  |
          *
221 |  |
          * <h3>ObjectRenderers</h3>
222 |  |
          *
223 |  |
          * You can customize the way message objects of a given type are converted
224 |  |
          * to String before being logged. This is done by specifying an
225 |  |
          * {@link org.apache.log4j.or.ObjectRenderer ObjectRenderer}for the object
226 |  |
          * type would like to customize.
227 |  |
          *
228 |  |
          * <p>
229 |  |
          * The syntax is:
230 |  |
          *
231 |  |
          * <pre>
232 |  |
          * log4j.renderer.fully.qualified.name.of.rendered.class = fully.qualified.name.of.rendering.class
233 |  |
          * </pre>
234 |  |
          *
235 |  |
          * As in,
236 |  |
          *
237 |  |
          * <pre>
238 |  |
          * log4j.renderer.my.Fruit = my.FruitRenderer
239 |  |
          * </pre>
240 |  |
          *
241 |  |
          * <h3>Logger Factories</h3>
242 |  |
          *
243 |  |
          * The usage of custom logger factories is discouraged and no longer
244 |  |
          * documented.
245 |  |
          *
246 |  |
          * <h3>Example</h3>
247 |  |
          *
248 |  |
          * <p>
249 |  |
          * An example configuration is given below. Other configuration file
250 |  |
          * examples are given in the <code>examples</code> folder.
251 |  |
          *
252 |  |
          * <pre>
253 |  |
          *
254 |  |
          *
255 |  |
          *
256 |  |
          *
257 |  |
          *        # Set options for appender named &quot;A1&quot;.
258 |  |
          *        # Appender &quot;A1&quot; will be a SyslogAppender
259 |  |
          *        log4j.appender.A1=org.apache.log4j.net.SyslogAppender
260 |  |
          *
261 |  |
          *        # The syslog daemon resides on www.abc.net
262 |  |
          *        log4j.appender.A1.SyslogHost=www.abc.net
263 |  |
          *
264 |  |
          *        # A1's layout is a PatternLayout, using the conversion pattern
265 |  |
          *        # &lt;b&gt;%r %-5p %c{2} %M.%L %x - %m\n&lt;/b&gt;. Thus, the log output will
266 |  |
          *        # include # the relative time since the start of the application in
267 |  |
          *        # milliseconds, followed by the level of the log request,
268 |  |
          *        # followed by the two rightmost components of the logger name,
269 |  |
          *        # followed by the callers method name, followed by the line number,
270 |  |
          *        # the nested disgnostic context and finally the message itself.
271 |  |
          *        # Refer to the documentation of {@link PatternLayout} for further information
272 |  |
          *        # on the syntax of the ConversionPattern key.
273 |  |
          *        log4j.appender.A1.layout=org.apache.log4j.PatternLayout
274 |  |
          *        log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
275 |  |
          *
276 |  |
          *        # Set options for appender named &quot;A2&quot;
277 |  |
          *        # A2 should be a RollingFileAppender, with maximum file size of 10 MB
278 |  |
          *        # using at most one backup file. A2's layout is TTCC, using the
279 |  |
          *        # ISO8061 date format with context printing enabled.
280 |  |
          *        log4j.appender.A2=org.apache.log4j.RollingFileAppender
281 |  |
          *        log4j.appender.A2.MaxFileSize=10MB
282 |  |
          *        log4j.appender.A2.MaxBackupIndex=1
283 |  |
          *        log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
284 |  |
          *        log4j.appender.A2.layout.ContextPrinting=enabled
285 |  |
          *        log4j.appender.A2.layout.DateFormat=ISO8601
286 |  |
          *
287 |  |
          *        # Root logger set to DEBUG using the A2 appender defined above.
288 |  |
          *        log4j.rootLogger=DEBUG, A2
289 |  |
          *
290 |  |
          *        # Logger definitions:
291 |  |
          *        # The SECURITY logger inherits is level from root. However, it's output
292 |  |
          *        # will go to A1 appender defined above. It's additivity is non-cumulative.
293 |  |
          *        log4j.logger.SECURITY=INHERIT, A1
294 |  |
          *        log4j.additivity.SECURITY=false
295 |  |
          *
296 |  |
          *        # Only warnings or above will be logged for the logger &quot;SECURITY.access&quot;.
297 |  |
          *        # Output will go to A1.
298 |  |
          *        log4j.logger.SECURITY.access=WARN
299 |  |
          *
300 |  |
          *
301 |  |
          *        # The logger &quot;class.of.the.day&quot; inherits its level from the
302 |  |
          *        # logger hierarchy.  Output will go to the appender's of the root
303 |  |
          *        # logger, A2 in this case.
304 |  |
          *        log4j.logger.class.of.the.day=INHERIT
305 |  |
          *
306 |  |
          *
307 |  |
          *
308 |  |
          * </pre>
309 |  |
          *
310 |  |
          * <p>
311 |  |
          * Refer to the <b>setOption </b> method in each Appender and Layout for
312 |  |
          * class specific options.
313 |  |
          *
314 |  |
          * <p>
315 |  |
          * Use the <code>#</code> or <code>!</code> characters at the beginning
316 |  |
          * of a line for comments.
317 |  |
          *
318 |  |
          * <p>
319 |  |
          *
320 |  |
          * @param configFileName
321 |  |
          *               The name of the configuration file where the configuration
322 |  |
          *               information is stored.
323 |  |
          *
324 |  |
          */
325 | 0 |
         public void doConfigure(String configFileName, LoggerRepository hierarchy) {
326 | 0 |
             Properties props = new Properties();
327 | 0 |
             try {
328 | 0 |
                 FileInputStream istream = new FileInputStream(configFileName);
329 | 0 |
                 props.load(istream);
330 | 0 |
                 istream.close();
331 |  |
             } catch (IOException e) {
332 | 0 |
                 LogLog.error("Could not read configuration file [" + configFileName
333 |  |
                         + "].", e);
334 | 0 |
                 LogLog.error("Ignoring configuration file [" + configFileName
335 |  |
                         + "].");
336 | 0 |
                 return;
337 |  |
             }
338 |  |
             // If we reach here, then the config file is alright.
339 | 0 |
             doConfigure(props, hierarchy);
340 |  |
         }
341 |  |
342 |  |
         /**
343 |  |
          */
344 | 0 |
         static public void configure(String configFilename) {
345 | 0 |
             new PropertyConfigurator().doConfigure(configFilename, LogManager
346 |  |
                     .getLoggerRepository());
347 |  |
         }
348 |  |
349 |  |
         /**
350 |  |
          * Read configuration options from url <code>configURL</code>.
351 |  |
          *
352 |  |
          * @since 0.8.2
353 |  |
          */
354 | 0 |
         public static void configure(java.net.URL configURL) {
355 | 0 |
             new PropertyConfigurator().doConfigure(configURL, LogManager
356 |  |
                     .getLoggerRepository());
357 |  |
         }
358 |  |
359 |  |
         /**
360 |  |
          * Read configuration options from <code>properties</code>.
361 |  |
          *
362 |  |
          * See {@link #doConfigure(String, LoggerRepository)}for the expected
363 |  |
          * format.
364 |  |
          */
365 | 0 |
         static public void configure(Properties properties) {
366 | 0 |
             new PropertyConfigurator().doConfigure(properties, LogManager
367 |  |
                     .getLoggerRepository());
368 |  |
         }
369 |  |
370 |  |
         /**
371 |  |
          * Like {@link #configureAndWatch(String, long)}except that the default
372 |  |
          * delay as defined by {@link FileWatchdog#DEFAULT_DELAY}is used.
373 |  |
          *
374 |  |
          * @param configFilename
375 |  |
          *               A file in key=value format.
376 |  |
          *
377 |  |
          */
378 | 0 |
         static public void configureAndWatch(String configFilename) {
379 | 0 |
             configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
380 |  |
         }
381 |  |
382 |  |
         /**
383 |  |
          * Read the configuration file <code>configFilename</code> if it exists.
384 |  |
          * Moreover, a thread will be created that will periodically check if
385 |  |
          * <code>configFilename</code> has been created or modified. The period is
386 |  |
          * determined by the <code>delay</code> argument. If a change or file
387 |  |
          * creation is detected, then <code>configFilename</code> is read to
388 |  |
          * configure log4j.
389 |  |
          *
390 |  |
          * @param configFilename
391 |  |
          *               A file in key=value format.
392 |  |
          * @param delay
393 |  |
          *               The delay in milliseconds to wait between each check.
394 |  |
          */
395 | 0 |
         static public void configureAndWatch(String configFilename, long delay) {
396 | 0 |
             PropertyWatchdog pdog = new PropertyWatchdog(configFilename);
397 | 0 |
             pdog.setDelay(delay);
398 | 0 |
             pdog.start();
399 |  |
         }
400 |  |
401 |  |
         /**
402 |  |
          * Read configuration options from <code>properties</code>.
403 |  |
          *
404 |  |
          * See {@link #doConfigure(String, LoggerRepository)}for the expected
405 |  |
          * format.
406 |  |
          *
407 |  |
          * @deprecated
408 |  |
          */
409 | 0 |
         public void doConfigure(Properties properties, LoggerRepository hierarchy) {
410 |  |
411 | 0 |
             String value = properties.getProperty(LogLog.DEBUG_KEY);
412 | 0 |
             if (value == null) {
413 | 0 |
                 value = properties.getProperty(LogLog.CONFIG_DEBUG_KEY);
414 | 0 |
                 if (value != null)
415 | 0 |
                     LogLog
416 |  |
                             .warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
417 |  |
             }
418 |  |
419 | 0 |
             if (value != null) {
420 | 0 |
                 LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
421 |  |
             }
422 |  |
423 | 0 |
             String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
424 |  |
                     properties);
425 | 0 |
             if (thresholdStr != null) {
426 | 0 |
                 hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
427 |  |
                         Level.ALL));
428 | 0 |
                 LogLog.debug("Hierarchy threshold set to ["
429 |  |
                         + hierarchy.getThreshold() + "].");
430 |  |
             }
431 |  |
432 | 0 |
             configureRootCategory(properties, hierarchy);
433 | 0 |
             configureLoggerFactory(properties);
434 | 0 |
             parseCatsAndRenderers(properties, hierarchy);
435 |  |
436 | 0 |
             LogLog.debug("Finished configuring.");
437 |  |
             // We don't want to hold references to appenders preventing their
438 |  |
             // garbage collection.
439 | 0 |
             registry.clear();
440 |  |
         }
441 |  |
442 |  |
         /**
443 |  |
          * Read configuration options from url <code>configURL</code>.
444 |  |
          */
445 | 0 |
         public void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
446 | 0 |
             Properties props = new Properties();
447 | 0 |
             LogLog.debug("Reading configuration from URL " + configURL);
448 | 0 |
             try {
449 | 0 |
                 props.load(configURL.openStream());
450 |  |
             } catch (java.io.IOException e) {
451 | 0 |
                 LogLog.error("Could not read configuration file from URL ["
452 |  |
                         + configURL + "].", e);
453 | 0 |
                 LogLog.error("Ignoring configuration file [" + configURL + "].");
454 | 0 |
                 return;
455 |  |
             }
456 | 0 |
             doConfigure(props, hierarchy);
457 |  |
         }
458 |  |
459 |  |
         // --------------------------------------------------------------------------
460 |  |
         // Internal stuff
461 |  |
         // --------------------------------------------------------------------------
462 |  |
463 |  |
         /**
464 |  |
          * Check the provided <code>Properties</code> object for a
465 |  |
          * {@link org.apache.log4j.spi.LoggerFactory LoggerFactory}entry specified
466 |  |
          * by {@link #LOGGER_FACTORY_KEY}. If such an entry exists, an attempt is
467 |  |
          * made to create an instance using the default constructor. This instance
468 |  |
          * is used for subsequent Category creations within this configurator.
469 |  |
          *
470 |  |
          * @see #parseCatsAndRenderers
471 |  |
          */
472 | 0 |
         protected void configureLoggerFactory(Properties props) {
473 | 0 |
             String factoryClassName = OptionConverter.findAndSubst(
474 |  |
                     LOGGER_FACTORY_KEY, props);
475 | 0 |
             if (factoryClassName != null) {
476 | 0 |
                 LogLog.debug("Setting category factory to [" + factoryClassName
477 |  |
                         + "].");
478 | 0 |
                 loggerFactory = (LoggerFactory) OptionConverter
479 |  |
                         .instantiateByClassName(factoryClassName,
480 |  |
                                 LoggerFactory.class, loggerFactory);
481 | 0 |
                 PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX
482 |  |
                         + ".");
483 |  |
             }
484 |  |
         }
485 |  |
486 |  |
         /*
487 |  |
          * void configureOptionHandler(OptionHandler oh, String prefix, Properties
488 |  |
          * props) { String[] options = oh.getOptionStrings(); if(options == null)
489 |  |
          * return;
490 |  |
          *
491 |  |
          * String value; for(int i = 0; i < options.length; i++) { value =
492 |  |
          * OptionConverter.findAndSubst(prefix + options[i], props); LogLog.debug(
493 |  |
          * "Option " + options[i] + "=[" + (value == null? "N/A" : value)+"]."); //
494 |  |
          * Some option handlers assume that null value are not passed to them. // So
495 |  |
          * don't remove this check if(value != null) { oh.setOption(options[i],
496 |  |
          * value); } } oh.activateOptions(); }
497 |  |
          */
498 |  |
499 | 0 |
         protected void configureRootCategory(Properties props,
500 |  |
                 LoggerRepository hierarchy) {
501 | 0 |
             String effectiveFrefix = ROOT_LOGGER_PREFIX;
502 | 0 |
             String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
503 |  |
504 | 0 |
             if (value == null) {
505 | 0 |
                 value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
506 | 0 |
                 effectiveFrefix = ROOT_CATEGORY_PREFIX;
507 |  |
             }
508 |  |
509 | 0 |
             if (value == null)
510 | 0 |
                 LogLog.debug("Could not find root logger information. Is this OK?");
511 |  |
             else {
512 | 0 |
                 Logger root = hierarchy.getRootLogger();
513 | 0 |
                 synchronized (root) {
514 | 0 |
                     parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME,
515 |  |
                             value);
516 |  |
                 }
517 |  |
             }
518 |  |
         }
519 |  |
520 |  |
         /**
521 |  |
          * Parse non-root elements, such non-root categories and renderers.
522 |  |
          */
523 | 0 |
         protected void parseCatsAndRenderers(Properties props,
524 |  |
                 LoggerRepository hierarchy) {
525 | 0 |
             Enumeration enum = props.propertyNames();
526 | 0 |
             while (enum.hasMoreElements()) {
527 | 0 |
                 String key = (String) enum.nextElement();
528 | 0 |
                 if (key.startsWith(CATEGORY_PREFIX)
529 |  |
                         || key.startsWith(LOGGER_PREFIX)) {
530 | 0 |
                     String loggerName = null;
531 | 0 |
                     if (key.startsWith(CATEGORY_PREFIX)) {
532 | 0 |
                         loggerName = key.substring(CATEGORY_PREFIX.length());
533 | 0 |
                     } else if (key.startsWith(LOGGER_PREFIX)) {
534 | 0 |
                         loggerName = key.substring(LOGGER_PREFIX.length());
535 |  |
                     }
536 | 0 |
                     String value = OptionConverter.findAndSubst(key, props);
537 | 0 |
                     Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
538 | 0 |
                     synchronized (logger) {
539 | 0 |
                         parseCategory(props, logger, key, loggerName, value);
540 | 0 |
                         parseAdditivityForLogger(props, logger, loggerName);
541 |  |
                     }
542 | 0 |
                 } else if (key.startsWith(RENDERER_PREFIX)) {
543 | 0 |
                     String renderedClass = key.substring(RENDERER_PREFIX.length());
544 | 0 |
                     String renderingClass = OptionConverter
545 |  |
                             .findAndSubst(key, props);
546 | 0 |
                     if (hierarchy instanceof RendererSupport) {
547 | 0 |
                         RendererMap.addRenderer((RendererSupport) hierarchy,
548 |  |
                                 renderedClass, renderingClass);
549 |  |
                     }
550 |  |
                 }
551 |  |
             }
552 |  |
         }
553 |  |
554 |  |
         /**
555 |  |
          * Parse the additivity option for a non-root category.
556 |  |
          */
557 | 0 |
         protected void parseAdditivityForLogger(Properties props, Logger cat,
558 |  |
                 String loggerName) {
559 | 0 |
             String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX
560 |  |
                     + loggerName, props);
561 | 0 |
             LogLog.debug("Handling " + ADDITIVITY_PREFIX + loggerName + "=["
562 |  |
                     + value + "]");
563 |  |
             // touch additivity only if necessary
564 | 0 |
             if ((value != null) && (!value.equals(""))) {
565 | 0 |
                 boolean additivity = OptionConverter.toBoolean(value, true);
566 | 0 |
                 LogLog.debug("Setting additivity for \"" + loggerName + "\" to "
567 |  |
                         + additivity);
568 | 0 |
                 cat.setAdditivity(additivity);
569 |  |
             }
570 |  |
         }
571 |  |
572 |  |
         /**
573 |  |
          * This method must work for the root category as well.
574 |  |
          */
575 | 0 |
         protected void parseCategory(Properties props, Logger logger,
576 |  |
                 String optionKey, String loggerName, String value) {
577 |  |
578 | 0 |
             if (optionKey == null) {
579 |  |
                 //do nothing
580 |  |
             }
581 |  |
582 | 0 |
             LogLog.debug("Parsing for [" + loggerName + "] with value=[" + value
583 |  |
                     + "].");
584 |  |
             // We must skip over ',' but not white space
585 | 0 |
             StringTokenizer st = new StringTokenizer(value, ",");
586 |  |
587 |  |
             // If value is not in the form ", appender.." or "", then we should set
588 |  |
             // the level of the loggeregory.
589 |  |
590 | 0 |
             if (!(value.startsWith(",") || value.equals(""))) {
591 |  |
592 |  |
                 // just to be on the safe side...
593 | 0 |
                 if (!st.hasMoreTokens())
594 | 0 |
                     return;
595 |  |
596 | 0 |
                 String levelStr = st.nextToken();
597 | 0 |
                 LogLog.debug("Level token is [" + levelStr + "].");
598 |  |
599 |  |
                 // If the level value is inherited, set category level value to
600 |  |
                 // null. We also check that the user has not specified inherited for
601 |  |
                 // the
602 |  |
                 // root category.
603 | 0 |
                 if (INHERITED.equalsIgnoreCase(levelStr)
604 |  |
                         || NULL.equalsIgnoreCase(levelStr)) {
605 | 0 |
                     if (loggerName.equals(INTERNAL_ROOT_NAME)) {
606 | 0 |
                         LogLog.warn("The root logger cannot be set to null.");
607 |  |
                     } else {
608 | 0 |
                         logger.setLevel(null);
609 |  |
                     }
610 |  |
                 } else {
611 | 0 |
                     logger.setLevel(OptionConverter.toLevel(levelStr, Level.DEBUG));
612 |  |
                 }
613 | 0 |
                 LogLog.debug("Category " + loggerName + " set to "
614 |  |
                         + logger.getLevel());
615 |  |
             }
616 |  |
617 |  |
             // Begin by removing all existing appenders.
618 | 0 |
             logger.removeAllAppenders();
619 |  |
620 | 0 |
             Appender appender;
621 | 0 |
             String appenderName;
622 | 0 |
             while (st.hasMoreTokens()) {
623 | 0 |
                 appenderName = st.nextToken().trim();
624 | 0 |
                 if (appenderName == null || appenderName.equals(","))
625 | 0 |
                     continue;
626 | 0 |
                 LogLog.debug("Parsing appender named \"" + appenderName + "\".");
627 | 0 |
                 appender = parseAppender(props, appenderName);
628 | 0 |
                 if (appender != null) {
629 | 0 |
                     logger.addAppender(appender);
630 |  |
                 }
631 |  |
             }
632 |  |
         }
633 |  |
634 | 0 |
         protected Appender parseAppender(Properties props, String appenderName) {
635 | 0 |
             Appender appender = registryGet(appenderName);
636 | 0 |
             if ((appender != null)) {
637 | 0 |
                 LogLog.debug("Appender \"" + appenderName
638 |  |
                         + "\" was already parsed.");
639 | 0 |
                 return appender;
640 |  |
             }
641 |  |
             // Appender was not previously initialized.
642 | 0 |
             String prefix = APPENDER_PREFIX + appenderName;
643 | 0 |
             String layoutPrefix = prefix + ".layout";
644 |  |
645 | 0 |
             appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
646 |  |
                     org.apache.log4j.Appender.class, null);
647 | 0 |
             if (appender == null) {
648 | 0 |
                 LogLog.error("Could not instantiate appender named \""
649 |  |
                         + appenderName + "\".");
650 | 0 |
                 return null;
651 |  |
             }
652 | 0 |
             appender.setName(appenderName);
653 |  |
654 | 0 |
             if (appender instanceof OptionHandler) {
655 | 0 |
                 if (appender.requiresLayout()) {
656 | 0 |
                     Layout layout = (Layout) OptionConverter.instantiateByKey(
657 |  |
                             props, layoutPrefix, Layout.class, null);
658 | 0 |
                     if (layout != null) {
659 | 0 |
                         appender.setLayout(layout);
660 | 0 |
                         LogLog.debug("Parsing layout options for \"" + appenderName
661 |  |
                                 + "\".");
662 |  |
                         //configureOptionHandler(layout, layoutPrefix + ".",
663 |  |
                         // props);
664 | 0 |
                         PropertySetter.setProperties(layout, props, layoutPrefix
665 |  |
                                 + ".");
666 | 0 |
                         LogLog
667 |  |
                                 .debug("End of parsing for \"" + appenderName
668 |  |
                                         + "\".");
669 |  |
                     }
670 |  |
                 }
671 |  |
                 //configureOptionHandler((OptionHandler) appender, prefix + ".",
672 |  |
                 // props);
673 | 0 |
                 PropertySetter.setProperties(appender, props, prefix + ".");
674 | 0 |
                 LogLog.debug("Parsed \"" + appenderName + "\" options.");
675 |  |
             }
676 | 0 |
             registryPut(appender);
677 | 0 |
             return appender;
678 |  |
         }
679 |  |
680 | 0 |
         protected final void registryPut(Appender appender) {
681 | 0 |
             registry.put(appender.getName(), appender);
682 |  |
         }
683 |  |
684 | 0 |
         protected final Appender registryGet(String name) {
685 | 0 |
             return (Appender) registry.get(name);
686 |  |
         }
687 |  |
     }
688 |  |
689 |  |
     class PropertyWatchdog extends FileWatchdog {
690 |  |
691 | 0 |
         PropertyWatchdog(String filename) {
692 | 0 |
             super(filename);
693 |  |
         }
694 |  |
695 |  |
         /**
696 |  |
          * Call {@link PropertyConfigurator#configure(String)}with the
697 |  |
          * <code>filename</code> to reconfigure log4j.
698 |  |
          */
699 | 0 |
         public void doOnChange() {
700 | 0 |
             new PropertyConfigurator().doConfigure(filename, LogManager
701 |  |
                     .getLoggerRepository());
702 |  |
         }
703 |  |
     }