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  
19  package org.apache.commons.logging.impl;
20  
21  import java.io.InputStream;
22  import java.io.Serializable;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.security.AccessController;
26  import java.security.PrivilegedAction;
27  import java.text.DateFormat;
28  import java.text.SimpleDateFormat;
29  import java.util.Date;
30  import java.util.Properties;
31  
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogConfigurationException;
34  
35  /**
36   * <p>Simple implementation of Log that sends all enabled log messages,
37   * for all defined loggers, to System.err.  The following system properties
38   * are supported to configure the behavior of this logger:</p>
39   * <ul>
40   * <li><code>org.apache.commons.logging.simplelog.defaultlog</code> -
41   *     Default logging detail level for all instances of SimpleLog.
42   *     Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
43   *     If not specified, defaults to "info". </li>
44   * <li><code>org.apache.commons.logging.simplelog.log.xxxxx</code> -
45   *     Logging detail level for a SimpleLog instance named "xxxxx".
46   *     Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
47   *     If not specified, the default logging detail level is used.</li>
48   * <li><code>org.apache.commons.logging.simplelog.showlogname</code> -
49   *     Set to <code>true</code> if you want the Log instance name to be
50   *     included in output messages. Defaults to <code>false</code>.</li>
51   * <li><code>org.apache.commons.logging.simplelog.showShortLogname</code> -
52   *     Set to <code>true</code> if you want the last component of the name to be
53   *     included in output messages. Defaults to <code>true</code>.</li>
54   * <li><code>org.apache.commons.logging.simplelog.showdatetime</code> -
55   *     Set to <code>true</code> if you want the current date and time
56   *     to be included in output messages. Default is <code>false</code>.</li>
57   * <li><code>org.apache.commons.logging.simplelog.dateTimeFormat</code> -
58   *     The date and time format to be used in the output messages.
59   *     The pattern describing the date and time format is the same that is
60   *     used in <code>java.text.SimpleDateFormat</code>. If the format is not
61   *     specified or is invalid, the default format is used.
62   *     The default format is <code>yyyy/MM/dd HH:mm:ss:SSS zzz</code>.</li>
63   * </ul>
64   *
65   * <p>In addition to looking for system properties with the names specified
66   * above, this implementation also checks for a class loader resource named
67   * <code>"simplelog.properties"</code>, and includes any matching definitions
68   * from this resource (if it exists).</p>
69   *
70   * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
71   * @author Rod Waldhoff
72   * @author Robert Burrell Donkin
73   *
74   * @version $Id: SimpleLog.java 581090 2007-10-01 22:01:06Z dennisl $
75   */
76  public class SimpleLog implements Log, Serializable {
77  
78  
79      // ------------------------------------------------------- Class Attributes
80  
81      /** All system properties used by <code>SimpleLog</code> start with this */
82      static protected final String systemPrefix =
83          "org.apache.commons.logging.simplelog.";
84  
85      /** Properties loaded from simplelog.properties */
86      static protected final Properties simpleLogProps = new Properties();
87  
88      /** The default format to use when formating dates */
89      static protected final String DEFAULT_DATE_TIME_FORMAT =
90          "yyyy/MM/dd HH:mm:ss:SSS zzz";
91  
92      /** Include the instance name in the log message? */
93      static protected boolean showLogName = false;
94      /** Include the short name ( last component ) of the logger in the log
95       *  message. Defaults to true - otherwise we'll be lost in a flood of
96       *  messages without knowing who sends them.
97       */
98      static protected boolean showShortName = true;
99      /** Include the current time in the log message */
100     static protected boolean showDateTime = false;
101     /** The date and time format to use in the log message */
102     static protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
103 
104     /**
105      * Used to format times.
106      * <p>
107      * Any code that accesses this object should first obtain a lock on it,
108      * ie use synchronized(dateFormatter); this requirement was introduced
109      * in 1.1.1 to fix an existing thread safety bug (SimpleDateFormat.format
110      * is not thread-safe).
111      */
112     static protected DateFormat dateFormatter = null;
113 
114     // ---------------------------------------------------- Log Level Constants
115 
116 
117     /** "Trace" level logging. */
118     public static final int LOG_LEVEL_TRACE  = 1;
119     /** "Debug" level logging. */
120     public static final int LOG_LEVEL_DEBUG  = 2;
121     /** "Info" level logging. */
122     public static final int LOG_LEVEL_INFO   = 3;
123     /** "Warn" level logging. */
124     public static final int LOG_LEVEL_WARN   = 4;
125     /** "Error" level logging. */
126     public static final int LOG_LEVEL_ERROR  = 5;
127     /** "Fatal" level logging. */
128     public static final int LOG_LEVEL_FATAL  = 6;
129 
130     /** Enable all logging levels */
131     public static final int LOG_LEVEL_ALL    = (LOG_LEVEL_TRACE - 1);
132 
133     /** Enable no logging levels */
134     public static final int LOG_LEVEL_OFF    = (LOG_LEVEL_FATAL + 1);
135 
136     // ------------------------------------------------------------ Initializer
137 
138     private static String getStringProperty(String name) {
139         String prop = null;
140         try {
141             prop = System.getProperty(name);
142         } catch (SecurityException e) {
143             ; // Ignore
144         }
145         return (prop == null) ? simpleLogProps.getProperty(name) : prop;
146     }
147 
148     private static String getStringProperty(String name, String dephault) {
149         String prop = getStringProperty(name);
150         return (prop == null) ? dephault : prop;
151     }
152 
153     private static boolean getBooleanProperty(String name, boolean dephault) {
154         String prop = getStringProperty(name);
155         return (prop == null) ? dephault : "true".equalsIgnoreCase(prop);
156     }
157 
158     // Initialize class attributes.
159     // Load properties file, if found.
160     // Override with system properties.
161     static {
162         // Add props from the resource simplelog.properties
163         InputStream in = getResourceAsStream("simplelog.properties");
164         if(null != in) {
165             try {
166                 simpleLogProps.load(in);
167                 in.close();
168             } catch(java.io.IOException e) {
169                 // ignored
170             }
171         }
172 
173         showLogName = getBooleanProperty( systemPrefix + "showlogname", showLogName);
174         showShortName = getBooleanProperty( systemPrefix + "showShortLogname", showShortName);
175         showDateTime = getBooleanProperty( systemPrefix + "showdatetime", showDateTime);
176 
177         if(showDateTime) {
178             dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat",
179                                                dateTimeFormat);
180             try {
181                 dateFormatter = new SimpleDateFormat(dateTimeFormat);
182             } catch(IllegalArgumentException e) {
183                 // If the format pattern is invalid - use the default format
184                 dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
185                 dateFormatter = new SimpleDateFormat(dateTimeFormat);
186             }
187         }
188     }
189 
190     // ------------------------------------------------------------- Attributes
191 
192     /** The name of this simple log instance */
193     protected String logName = null;
194     /** The current log level */
195     protected int currentLogLevel;
196     /** The short name of this simple log instance */
197     private String shortLogName = null;
198 
199 
200     // ------------------------------------------------------------ Constructor
201 
202     /**
203      * Construct a simple log with given name.
204      *
205      * @param name log name
206      */
207     public SimpleLog(String name) {
208 
209         logName = name;
210 
211         // Set initial log level
212         // Used to be: set default log level to ERROR
213         // IMHO it should be lower, but at least info ( costin ).
214         setLevel(SimpleLog.LOG_LEVEL_INFO);
215 
216         // Set log level from properties
217         String lvl = getStringProperty(systemPrefix + "log." + logName);
218         int i = String.valueOf(name).lastIndexOf(".");
219         while(null == lvl && i > -1) {
220             name = name.substring(0,i);
221             lvl = getStringProperty(systemPrefix + "log." + name);
222             i = String.valueOf(name).lastIndexOf(".");
223         }
224 
225         if(null == lvl) {
226             lvl =  getStringProperty(systemPrefix + "defaultlog");
227         }
228 
229         if("all".equalsIgnoreCase(lvl)) {
230             setLevel(SimpleLog.LOG_LEVEL_ALL);
231         } else if("trace".equalsIgnoreCase(lvl)) {
232             setLevel(SimpleLog.LOG_LEVEL_TRACE);
233         } else if("debug".equalsIgnoreCase(lvl)) {
234             setLevel(SimpleLog.LOG_LEVEL_DEBUG);
235         } else if("info".equalsIgnoreCase(lvl)) {
236             setLevel(SimpleLog.LOG_LEVEL_INFO);
237         } else if("warn".equalsIgnoreCase(lvl)) {
238             setLevel(SimpleLog.LOG_LEVEL_WARN);
239         } else if("error".equalsIgnoreCase(lvl)) {
240             setLevel(SimpleLog.LOG_LEVEL_ERROR);
241         } else if("fatal".equalsIgnoreCase(lvl)) {
242             setLevel(SimpleLog.LOG_LEVEL_FATAL);
243         } else if("off".equalsIgnoreCase(lvl)) {
244             setLevel(SimpleLog.LOG_LEVEL_OFF);
245         }
246 
247     }
248 
249 
250     // -------------------------------------------------------- Properties
251 
252     /**
253      * <p> Set logging level. </p>
254      *
255      * @param currentLogLevel new logging level
256      */
257     public void setLevel(int currentLogLevel) {
258 
259         this.currentLogLevel = currentLogLevel;
260 
261     }
262 
263 
264     /**
265      * <p> Get logging level. </p>
266      */
267     public int getLevel() {
268 
269         return currentLogLevel;
270     }
271 
272 
273     // -------------------------------------------------------- Logging Methods
274 
275 
276     /**
277      * <p> Do the actual logging.
278      * This method assembles the message
279      * and then calls <code>write()</code> to cause it to be written.</p>
280      *
281      * @param type One of the LOG_LEVEL_XXX constants defining the log level
282      * @param message The message itself (typically a String)
283      * @param t The exception whose stack trace should be logged
284      */
285     protected void log(int type, Object message, Throwable t) {
286         // Use a string buffer for better performance
287         StringBuffer buf = new StringBuffer();
288 
289         // Append date-time if so configured
290         if(showDateTime) {
291             Date now = new Date();
292             String dateText;
293             synchronized(dateFormatter) {
294                 dateText = dateFormatter.format(now);
295             }
296             buf.append(dateText);
297             buf.append(" ");
298         }
299 
300         // Append a readable representation of the log level
301         switch(type) {
302             case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break;
303             case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break;
304             case SimpleLog.LOG_LEVEL_INFO:  buf.append("[INFO] ");  break;
305             case SimpleLog.LOG_LEVEL_WARN:  buf.append("[WARN] ");  break;
306             case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break;
307             case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break;
308         }
309 
310         // Append the name of the log instance if so configured
311         if( showShortName) {
312             if( shortLogName==null ) {
313                 // Cut all but the last component of the name for both styles
314                 shortLogName = logName.substring(logName.lastIndexOf(".") + 1);
315                 shortLogName =
316                     shortLogName.substring(shortLogName.lastIndexOf("/") + 1);
317             }
318             buf.append(String.valueOf(shortLogName)).append(" - ");
319         } else if(showLogName) {
320             buf.append(String.valueOf(logName)).append(" - ");
321         }
322 
323         // Append the message
324         buf.append(String.valueOf(message));
325 
326         // Append stack trace if not null
327         if(t != null) {
328             buf.append(" <");
329             buf.append(t.toString());
330             buf.append(">");
331 
332             java.io.StringWriter sw= new java.io.StringWriter(1024);
333             java.io.PrintWriter pw= new java.io.PrintWriter(sw);
334             t.printStackTrace(pw);
335             pw.close();
336             buf.append(sw.toString());
337         }
338 
339         // Print to the appropriate destination
340         write(buf);
341 
342     }
343 
344 
345     /**
346      * <p>Write the content of the message accumulated in the specified
347      * <code>StringBuffer</code> to the appropriate output destination.  The
348      * default implementation writes to <code>System.err</code>.</p>
349      *
350      * @param buffer A <code>StringBuffer</code> containing the accumulated
351      *  text to be logged
352      */
353     protected void write(StringBuffer buffer) {
354 
355         System.err.println(buffer.toString());
356 
357     }
358 
359 
360     /**
361      * Is the given log level currently enabled?
362      *
363      * @param logLevel is this level enabled?
364      */
365     protected boolean isLevelEnabled(int logLevel) {
366         // log level are numerically ordered so can use simple numeric
367         // comparison
368         return (logLevel >= currentLogLevel);
369     }
370 
371 
372     // -------------------------------------------------------- Log Implementation
373 
374 
375     /**
376      * Logs a message with 
377      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
378      *
379      * @param message to log
380      * @see org.apache.commons.logging.Log#debug(Object)
381      */
382     public final void debug(Object message) {
383 
384         if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
385             log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
386         }
387     }
388 
389 
390     /**
391      * Logs a message with 
392      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
393      *
394      * @param message to log
395      * @param t log this cause
396      * @see org.apache.commons.logging.Log#debug(Object, Throwable)
397      */
398     public final void debug(Object message, Throwable t) {
399 
400         if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
401             log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
402         }
403     }
404 
405 
406     /**
407      * Logs a message with 
408      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
409      *
410      * @param message to log
411      * @see org.apache.commons.logging.Log#trace(Object)
412      */
413     public final void trace(Object message) {
414 
415         if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
416             log(SimpleLog.LOG_LEVEL_TRACE, message, null);
417         }
418     }
419 
420 
421     /**
422      * Logs a message with 
423      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
424      *
425      * @param message to log
426      * @param t log this cause
427      * @see org.apache.commons.logging.Log#trace(Object, Throwable)
428      */
429     public final void trace(Object message, Throwable t) {
430 
431         if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
432             log(SimpleLog.LOG_LEVEL_TRACE, message, t);
433         }
434     }
435 
436 
437     /**
438      * Logs a message with 
439      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
440      *
441      * @param message to log
442      * @see org.apache.commons.logging.Log#info(Object)
443      */
444     public final void info(Object message) {
445 
446         if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
447             log(SimpleLog.LOG_LEVEL_INFO,message,null);
448         }
449     }
450 
451 
452     /**
453      * Logs a message with 
454      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
455      *
456      * @param message to log
457      * @param t log this cause
458      * @see org.apache.commons.logging.Log#info(Object, Throwable)
459      */
460     public final void info(Object message, Throwable t) {
461 
462         if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
463             log(SimpleLog.LOG_LEVEL_INFO, message, t);
464         }
465     }
466 
467 
468     /**
469      * Logs a message with 
470      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
471      *
472      * @param message to log
473      * @see org.apache.commons.logging.Log#warn(Object)
474      */
475     public final void warn(Object message) {
476 
477         if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
478             log(SimpleLog.LOG_LEVEL_WARN, message, null);
479         }
480     }
481 
482 
483     /**
484      * Logs a message with 
485      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
486      *
487      * @param message to log
488      * @param t log this cause
489      * @see org.apache.commons.logging.Log#warn(Object, Throwable)
490      */
491     public final void warn(Object message, Throwable t) {
492 
493         if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
494             log(SimpleLog.LOG_LEVEL_WARN, message, t);
495         }
496     }
497 
498 
499     /**
500      * Logs a message with 
501      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
502      *
503      * @param message to log
504      * @see org.apache.commons.logging.Log#error(Object)
505      */
506     public final void error(Object message) {
507 
508         if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
509             log(SimpleLog.LOG_LEVEL_ERROR, message, null);
510         }
511     }
512 
513 
514     /**
515      * Logs a message with 
516      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
517      *
518      * @param message to log
519      * @param t log this cause
520      * @see org.apache.commons.logging.Log#error(Object, Throwable)
521      */
522     public final void error(Object message, Throwable t) {
523 
524         if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
525             log(SimpleLog.LOG_LEVEL_ERROR, message, t);
526         }
527     }
528 
529 
530     /**
531      * Log a message with 
532      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
533      *
534      * @param message to log
535      * @see org.apache.commons.logging.Log#fatal(Object)
536      */
537     public final void fatal(Object message) {
538 
539         if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
540             log(SimpleLog.LOG_LEVEL_FATAL, message, null);
541         }
542     }
543 
544 
545     /**
546      * Logs a message with 
547      * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
548      *
549      * @param message to log
550      * @param t log this cause
551      * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
552      */
553     public final void fatal(Object message, Throwable t) {
554 
555         if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
556             log(SimpleLog.LOG_LEVEL_FATAL, message, t);
557         }
558     }
559 
560 
561     /**
562      * <p> Are debug messages currently enabled? </p>
563      *
564      * <p> This allows expensive operations such as <code>String</code>
565      * concatenation to be avoided when the message will be ignored by the
566      * logger. </p>
567      */
568     public final boolean isDebugEnabled() {
569 
570         return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG);
571     }
572 
573 
574     /**
575      * <p> Are error messages currently enabled? </p>
576      *
577      * <p> This allows expensive operations such as <code>String</code>
578      * concatenation to be avoided when the message will be ignored by the
579      * logger. </p>
580      */
581     public final boolean isErrorEnabled() {
582 
583         return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR);
584     }
585 
586 
587     /**
588      * <p> Are fatal messages currently enabled? </p>
589      *
590      * <p> This allows expensive operations such as <code>String</code>
591      * concatenation to be avoided when the message will be ignored by the
592      * logger. </p>
593      */
594     public final boolean isFatalEnabled() {
595 
596         return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL);
597     }
598 
599 
600     /**
601      * <p> Are info messages currently enabled? </p>
602      *
603      * <p> This allows expensive operations such as <code>String</code>
604      * concatenation to be avoided when the message will be ignored by the
605      * logger. </p>
606      */
607     public final boolean isInfoEnabled() {
608 
609         return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO);
610     }
611 
612 
613     /**
614      * <p> Are trace messages currently enabled? </p>
615      *
616      * <p> This allows expensive operations such as <code>String</code>
617      * concatenation to be avoided when the message will be ignored by the
618      * logger. </p>
619      */
620     public final boolean isTraceEnabled() {
621 
622         return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE);
623     }
624 
625 
626     /**
627      * <p> Are warn messages currently enabled? </p>
628      *
629      * <p> This allows expensive operations such as <code>String</code>
630      * concatenation to be avoided when the message will be ignored by the
631      * logger. </p>
632      */
633     public final boolean isWarnEnabled() {
634 
635         return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN);
636     }
637 
638 
639     /**
640      * Return the thread context class loader if available.
641      * Otherwise return null.
642      *
643      * The thread context class loader is available for JDK 1.2
644      * or later, if certain security conditions are met.
645      *
646      * @exception LogConfigurationException if a suitable class loader
647      * cannot be identified.
648      */
649     private static ClassLoader getContextClassLoader()
650     {
651         ClassLoader classLoader = null;
652 
653         if (classLoader == null) {
654             try {
655                 // Are we running on a JDK 1.2 or later system?
656                 Method method = Thread.class.getMethod("getContextClassLoader",
657                         (Class[]) null);
658 
659                 // Get the thread context class loader (if there is one)
660                 try {
661                     classLoader = (ClassLoader)method.invoke(Thread.currentThread(), 
662                             (Class[]) null);
663                 } catch (IllegalAccessException e) {
664                     ;  // ignore
665                 } catch (InvocationTargetException e) {
666                     /**
667                      * InvocationTargetException is thrown by 'invoke' when
668                      * the method being invoked (getContextClassLoader) throws
669                      * an exception.
670                      *
671                      * getContextClassLoader() throws SecurityException when
672                      * the context class loader isn't an ancestor of the
673                      * calling class's class loader, or if security
674                      * permissions are restricted.
675                      *
676                      * In the first case (not related), we want to ignore and
677                      * keep going.  We cannot help but also ignore the second
678                      * with the logic below, but other calls elsewhere (to
679                      * obtain a class loader) will trigger this exception where
680                      * we can make a distinction.
681                      */
682                     if (e.getTargetException() instanceof SecurityException) {
683                         ;  // ignore
684                     } else {
685                         // Capture 'e.getTargetException()' exception for details
686                         // alternate: log 'e.getTargetException()', and pass back 'e'.
687                         throw new LogConfigurationException
688                             ("Unexpected InvocationTargetException", e.getTargetException());
689                     }
690                 }
691             } catch (NoSuchMethodException e) {
692                 // Assume we are running on JDK 1.1
693                 ;  // ignore
694             }
695         }
696 
697         if (classLoader == null) {
698             classLoader = SimpleLog.class.getClassLoader();
699         }
700 
701         // Return the selected class loader
702         return classLoader;
703     }
704 
705     private static InputStream getResourceAsStream(final String name)
706     {
707         return (InputStream)AccessController.doPrivileged(
708             new PrivilegedAction() {
709                 public Object run() {
710                     ClassLoader threadCL = getContextClassLoader();
711 
712                     if (threadCL != null) {
713                         return threadCL.getResourceAsStream(name);
714                     } else {
715                         return ClassLoader.getSystemResourceAsStream(name);
716                     }
717                 }
718             });
719     }
720 }
721