Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / java / util / logging / LogManager.java
blob67dc76b7a42d620b803cf36651e2215b2fefe7dd
1 /* LogManager.java -- a class for maintaining Loggers and managing
2 configuration properties
3 Copyright (C) 2002 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package java.util.logging;
42 import java.beans.PropertyChangeListener;
43 import java.beans.PropertyChangeSupport;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.lang.ref.WeakReference;
47 import java.net.URL;
48 import java.util.Collections;
49 import java.util.Enumeration;
50 import java.util.Iterator;
51 import java.util.Map;
52 import java.util.Properties;
53 import java.util.StringTokenizer;
55 /**
56 * The <code>LogManager</code> maintains a hierarchical namespace
57 * of Logger objects and manages properties for configuring the logging
58 * framework. There exists only one single <code>LogManager</code>
59 * per virtual machine. This instance can be retrieved using the
60 * static method {@link #getLogManager()}.
62 * <p><strong>Configuration Process:</strong> The global LogManager
63 * object is created and configured when the class
64 * <code>java.util.logging.LogManager</code> is initialized.
65 * The configuration process includes the subsequent steps:
67 * <ul>
68 * <li>If the system property <code>java.util.logging.manager</code>
69 * is set to the name of a subclass of
70 * <code>java.util.logging.LogManager</code>, an instance of
71 * that subclass is created and becomes the global LogManager.
72 * Otherwise, a new instance of LogManager is created.</li>
73 * <li>The <code>LogManager</code> constructor tries to create
74 * a new instance of the class specified by the system
75 * property <code>java.util.logging.config.class</code>.
76 * Typically, the constructor of this class will call
77 * <code>LogManager.getLogManager().readConfiguration(java.io.InputStream)</code>
78 * for configuring the logging framework.
79 * The configuration process stops at this point if
80 * the system property <code>java.util.logging.config.class</code>
81 * is set (irrespective of whether the class constructor
82 * could be called or an exception was thrown).</li>
84 * <li>If the system property <code>java.util.logging.config.class</code>
85 * is <em>not</em> set, the configuration parameters are read in from
86 * a file and passed to
87 * {@link #readConfiguration(java.io.InputStream)}.
88 * The name and location of this file are specified by the system
89 * property <code>java.util.logging.config.file</code>.</li>
90 * <li>If the system property <code>java.util.logging.config.file</code>
91 * is not set, however, the contents of the URL
92 * "{gnu.classpath.home.url}/logging.properties" are passed to
93 * {@link #readConfiguration(java.io.InputStream)}.
94 * Here, "{gnu.classpath.home.url}" stands for the value of
95 * the system property <code>gnu.classpath.home.url</code>.</li>
96 * </ul>
98 * @author Sascha Brawer (brawer@acm.org)
100 public class LogManager
103 * The singleton LogManager instance.
105 private static LogManager logManager;
108 * The registered named loggers; maps the name of a Logger to
109 * a WeakReference to it.
111 private Map loggers;
112 final Logger rootLogger;
115 * The properties for the logging framework which have been
116 * read in last.
118 private Properties properties;
121 * A delegate object that provides support for handling
122 * PropertyChangeEvents. The API specification does not
123 * mention which bean should be the source in the distributed
124 * PropertyChangeEvents, but Mauve test code has determined that
125 * the Sun J2SE 1.4 reference implementation uses the LogManager
126 * class object. This is somewhat strange, as the class object
127 * is not the bean with which listeners have to register, but
128 * there is no reason for the GNU Classpath implementation to
129 * behave differently from the reference implementation in
130 * this case.
132 private final PropertyChangeSupport pcs = new PropertyChangeSupport( /* source bean */
133 LogManager.class);
135 protected LogManager()
137 if (logManager != null)
138 throw new IllegalStateException("there can be only one LogManager; use LogManager.getLogManager()");
140 logManager = this;
141 loggers = new java.util.HashMap();
142 rootLogger = new Logger("", null);
143 addLogger(rootLogger);
145 /* Make sure that Logger.global has the rootLogger as its parent.
147 * Logger.global is set during class initialization of Logger,
148 * which may or may not be before this code is being executed.
149 * For example, on the Sun 1.3.1 and 1.4.0 JVMs, Logger.global
150 * has been set before this code is being executed. In contrast,
151 * Logger.global still is null on GCJ 3.2. Since the LogManager
152 * and Logger classes are mutually dependent, both behaviors are
153 * correct.
155 * This means that we cannot depend on Logger.global to have its
156 * value when this code executes, although that variable is final.
157 * Since Logger.getLogger will always return the same logger for
158 * the same name, the subsequent line works fine irrespective of
159 * the order in which classes are initialized.
161 Logger.getLogger("global").setParent(rootLogger);
162 Logger.getLogger("global").setUseParentHandlers(true);
166 * Returns the globally shared LogManager instance.
168 public static LogManager getLogManager()
170 return logManager;
173 static
175 makeLogManager();
177 /* The Javadoc description of the class explains
178 * what is going on here.
180 Object configurator = createInstance(System.getProperty("java.util.logging.config.class"),
181 /* must be instance of */ Object.class);
185 if (configurator == null)
186 getLogManager().readConfiguration();
188 catch (IOException ex)
190 /* FIXME: Is it ok to ignore exceptions here? */
194 private static LogManager makeLogManager()
196 String managerClassName;
197 LogManager manager;
199 managerClassName = System.getProperty("java.util.logging.manager");
200 manager = (LogManager) createInstance(managerClassName, LogManager.class);
201 if (manager != null)
202 return manager;
204 if (managerClassName != null)
205 System.err.println("WARNING: System property \"java.util.logging.manager\""
206 + " should be the name of a subclass of java.util.logging.LogManager");
208 return new LogManager();
212 * Registers a listener which will be notified when the
213 * logging properties are re-read.
215 public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
217 /* do not register null. */
218 listener.getClass();
220 pcs.addPropertyChangeListener(listener);
224 * Unregisters a listener.
226 * If <code>listener</code> has not been registered previously,
227 * nothing happens. Also, no exception is thrown if
228 * <code>listener</code> is <code>null</code>.
230 public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
232 if (listener != null)
233 pcs.removePropertyChangeListener(listener);
237 * Adds a named logger. If a logger with the same name has
238 * already been registered, the method returns <code>false</code>
239 * without adding the logger.
241 * <p>The <code>LogManager</code> only keeps weak references
242 * to registered loggers. Therefore, names can become available
243 * after automatic garbage collection.
245 * @param logger the logger to be added.
247 * @return <code>true</code>if <code>logger</code> was added,
248 * <code>false</code> otherwise.
250 * @throws NullPointerException if <code>name</code> is
251 * <code>null</code>.
253 public synchronized boolean addLogger(Logger logger)
255 /* To developers thinking about to remove the 'synchronized'
256 * declaration from this method: Please read the comment
257 * in java.util.logging.Logger.getLogger(String, String)
258 * and make sure that whatever you change wrt. synchronization
259 * does not endanger thread-safety of Logger.getLogger.
260 * The current implementation of Logger.getLogger assumes
261 * that LogManager does its synchronization on the globally
262 * shared instance of LogManager.
264 String name;
265 WeakReference ref;
267 /* This will throw a NullPointerException if logger is null,
268 * as required by the API specification.
270 name = logger.getName();
272 ref = (WeakReference) loggers.get(name);
273 if (ref != null)
275 if (ref.get() != null)
276 return false;
278 /* There has been a logger under this name in the past,
279 * but it has been garbage collected.
281 loggers.remove(ref);
284 /* Adding a named logger requires a security permission. */
285 if ((name != null) && ! name.equals(""))
286 checkAccess();
288 Logger parent = findAncestor(logger);
289 loggers.put(name, new WeakReference(logger));
290 if (parent != logger.getParent())
291 logger.setParent(parent);
293 /* It can happen that existing loggers should be children of
294 * the newly added logger. For example, assume that there
295 * already exist loggers under the names "", "foo", and "foo.bar.baz".
296 * When adding "foo.bar", the logger "foo.bar.baz" should change
297 * its parent to "foo.bar".
299 if (parent != rootLogger)
301 for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();)
303 Logger possChild = (Logger) ((WeakReference) loggers.get(iter.next()))
304 .get();
305 if ((possChild == null) || (possChild == logger)
306 || (possChild.getParent() != parent))
307 continue;
309 if (! possChild.getName().startsWith(name))
310 continue;
312 if (possChild.getName().charAt(name.length()) != '.')
313 continue;
315 possChild.setParent(logger);
319 return true;
323 * Finds the closest ancestor for a logger among the currently
324 * registered ones. For example, if the currently registered
325 * loggers have the names "", "foo", and "foo.bar", the result for
326 * "foo.bar.baz" will be the logger whose name is "foo.bar".
328 * @param child a logger for whose name no logger has been
329 * registered.
331 * @return the closest ancestor for <code>child</code>,
332 * or <code>null</code> if <code>child</code>
333 * is the root logger.
335 * @throws NullPointerException if <code>child</code>
336 * is <code>null</code>.
338 private synchronized Logger findAncestor(Logger child)
340 String childName = child.getName();
341 int childNameLength = childName.length();
342 Logger best = rootLogger;
343 int bestNameLength = 0;
345 Logger cand;
346 String candName;
347 int candNameLength;
349 if (child == rootLogger)
350 return null;
352 for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();)
354 candName = (String) iter.next();
355 candNameLength = candName.length();
357 if (candNameLength > bestNameLength
358 && childNameLength > candNameLength
359 && childName.startsWith(candName)
360 && childName.charAt(candNameLength) == '.')
362 cand = (Logger) ((WeakReference) loggers.get(candName)).get();
363 if ((cand == null) || (cand == child))
364 continue;
366 bestNameLength = candName.length();
367 best = cand;
371 return best;
375 * Returns a Logger given its name.
377 * @param name the name of the logger.
379 * @return a named Logger, or <code>null</code> if there is no
380 * logger with that name.
382 * @throw java.lang.NullPointerException if <code>name</code>
383 * is <code>null</code>.
385 public synchronized Logger getLogger(String name)
387 WeakReference ref;
389 /* Throw a NullPointerException if name is null. */
390 name.getClass();
392 ref = (WeakReference) loggers.get(name);
393 if (ref != null)
394 return (Logger) ref.get();
395 else
396 return null;
400 * Returns an Enumeration of currently registered Logger names.
401 * Since other threads can register loggers at any time, the
402 * result could be different any time this method is called.
404 * @return an Enumeration with the names of the currently
405 * registered Loggers.
407 public synchronized Enumeration getLoggerNames()
409 return Collections.enumeration(loggers.keySet());
413 * Resets the logging configuration by removing all handlers for
414 * registered named loggers and setting their level to <code>null</code>.
415 * The level of the root logger will be set to <code>Level.INFO</code>.
417 * @throws SecurityException if a security manager exists and
418 * the caller is not granted the permission to control
419 * the logging infrastructure.
421 public synchronized void reset() throws SecurityException
423 /* Throw a SecurityException if the caller does not have the
424 * permission to control the logging infrastructure.
426 checkAccess();
428 properties = new Properties();
430 Iterator iter = loggers.values().iterator();
431 while (iter.hasNext())
433 WeakReference ref;
434 Logger logger;
436 ref = (WeakReference) iter.next();
437 if (ref != null)
439 logger = (Logger) ref.get();
441 if (logger == null)
442 iter.remove();
443 else if (logger != rootLogger)
444 logger.setLevel(null);
448 rootLogger.setLevel(Level.INFO);
452 * Configures the logging framework by reading a configuration file.
453 * The name and location of this file are specified by the system
454 * property <code>java.util.logging.config.file</code>. If this
455 * property is not set, the URL
456 * "{gnu.classpath.home.url}/logging.properties" is taken, where
457 * "{gnu.classpath.home.url}" stands for the value of the system
458 * property <code>gnu.classpath.home.url</code>.
460 * <p>The task of configuring the framework is then delegated to
461 * {@link #readConfiguration(java.io.InputStream)}, which will
462 * notify registered listeners after having read the properties.
464 * @throws SecurityException if a security manager exists and
465 * the caller is not granted the permission to control
466 * the logging infrastructure, or if the caller is
467 * not granted the permission to read the configuration
468 * file.
470 * @throws IOException if there is a problem reading in the
471 * configuration file.
473 public synchronized void readConfiguration()
474 throws IOException, SecurityException
476 String path;
477 InputStream inputStream;
479 path = System.getProperty("java.util.logging.config.file");
480 if ((path == null) || (path.length() == 0))
482 String url = (System.getProperty("gnu.classpath.home.url")
483 + "/logging.properties");
484 inputStream = new URL(url).openStream();
486 else
487 inputStream = new java.io.FileInputStream(path);
491 readConfiguration(inputStream);
493 finally
495 /* Close the stream in order to save
496 * resources such as file descriptors.
498 inputStream.close();
502 public synchronized void readConfiguration(InputStream inputStream)
503 throws IOException, SecurityException
505 Properties newProperties;
506 Enumeration keys;
508 checkAccess();
509 newProperties = new Properties();
510 newProperties.load(inputStream);
511 this.properties = newProperties;
512 keys = newProperties.propertyNames();
514 while (keys.hasMoreElements())
516 String key = ((String) keys.nextElement()).trim();
517 String value = newProperties.getProperty(key);
519 if (value == null)
520 continue;
522 value = value.trim();
524 if ("handlers".equals(key))
526 StringTokenizer tokenizer = new StringTokenizer(value);
527 while (tokenizer.hasMoreTokens())
529 String handlerName = tokenizer.nextToken();
532 Class handlerClass = Class.forName(handlerName);
533 getLogger("").addHandler((Handler) handlerClass
534 .newInstance());
536 catch (ClassCastException ex)
538 System.err.println("[LogManager] class " + handlerName
539 + " is not subclass of java.util.logging.Handler");
541 catch (Exception ex)
543 //System.out.println("[LogManager.readConfiguration]"+ex);
548 if (key.endsWith(".level"))
550 String loggerName = key.substring(0, key.length() - 6);
551 Logger logger = getLogger(loggerName);
553 if (logger == null)
555 logger = Logger.getLogger(loggerName);
556 addLogger(logger);
560 logger.setLevel(Level.parse(value));
562 catch (Exception _)
564 //System.out.println("[LogManager.readConfiguration] "+_);
566 continue;
570 /* The API specification does not talk about the
571 * property name that is distributed with the
572 * PropertyChangeEvent. With test code, it could
573 * be determined that the Sun J2SE 1.4 reference
574 * implementation uses null for the property name.
576 pcs.firePropertyChange(null, null, null);
580 * Returns the value of a configuration property as a String.
582 public synchronized String getProperty(String name)
584 if (properties != null)
585 return properties.getProperty(name);
586 else
587 return null;
591 * Returns the value of a configuration property as an integer.
592 * This function is a helper used by the Classpath implementation
593 * of java.util.logging, it is <em>not</em> specified in the
594 * logging API.
596 * @param name the name of the configuration property.
598 * @param defaultValue the value that will be returned if the
599 * property is not defined, or if its value is not an integer
600 * number.
602 static int getIntProperty(String name, int defaultValue)
606 return Integer.parseInt(getLogManager().getProperty(name));
608 catch (Exception ex)
610 return defaultValue;
615 * Returns the value of a configuration property as an integer,
616 * provided it is inside the acceptable range.
617 * This function is a helper used by the Classpath implementation
618 * of java.util.logging, it is <em>not</em> specified in the
619 * logging API.
621 * @param name the name of the configuration property.
623 * @param minValue the lowest acceptable value.
625 * @param maxValue the highest acceptable value.
627 * @param defaultValue the value that will be returned if the
628 * property is not defined, or if its value is not an integer
629 * number, or if it is less than the minimum value,
630 * or if it is greater than the maximum value.
632 static int getIntPropertyClamped(String name, int defaultValue,
633 int minValue, int maxValue)
635 int val = getIntProperty(name, defaultValue);
636 if ((val < minValue) || (val > maxValue))
637 val = defaultValue;
638 return val;
642 * Returns the value of a configuration property as a boolean.
643 * This function is a helper used by the Classpath implementation
644 * of java.util.logging, it is <em>not</em> specified in the
645 * logging API.
647 * @param name the name of the configuration property.
649 * @param defaultValue the value that will be returned if the
650 * property is not defined, or if its value is neither
651 * <code>"true"</code> nor <code>"false"</code>.
653 static boolean getBooleanProperty(String name, boolean defaultValue)
657 return (new Boolean(getLogManager().getProperty(name))).booleanValue();
659 catch (Exception ex)
661 return defaultValue;
666 * Returns the value of a configuration property as a Level.
667 * This function is a helper used by the Classpath implementation
668 * of java.util.logging, it is <em>not</em> specified in the
669 * logging API.
671 * @param propertyName the name of the configuration property.
673 * @param defaultValue the value that will be returned if the
674 * property is not defined, or if
675 * {@link Level.parse(java.lang.String)} does not like
676 * the property value.
678 static Level getLevelProperty(String propertyName, Level defaultValue)
682 return Level.parse(getLogManager().getProperty(propertyName));
684 catch (Exception ex)
686 return defaultValue;
691 * Returns the value of a configuration property as a Class.
692 * This function is a helper used by the Classpath implementation
693 * of java.util.logging, it is <em>not</em> specified in the
694 * logging API.
696 * @param propertyName the name of the configuration property.
698 * @param defaultValue the value that will be returned if the
699 * property is not defined, or if it does not specify
700 * the name of a loadable class.
702 static final Class getClassProperty(String propertyName, Class defaultValue)
704 Class usingClass = null;
708 String propertyValue = logManager.getProperty(propertyName);
709 if (propertyValue != null)
710 usingClass = Class.forName(propertyValue);
711 if (usingClass != null)
712 return usingClass;
714 catch (Exception _)
718 return defaultValue;
721 static final Object getInstanceProperty(String propertyName, Class ofClass,
722 Class defaultClass)
724 Class klass = getClassProperty(propertyName, defaultClass);
725 if (klass == null)
726 return null;
730 Object obj = klass.newInstance();
731 if (ofClass.isInstance(obj))
732 return obj;
734 catch (Exception _)
738 if (defaultClass == null)
739 return null;
743 return defaultClass.newInstance();
745 catch (java.lang.InstantiationException ex)
747 throw new RuntimeException(ex.getMessage());
749 catch (java.lang.IllegalAccessException ex)
751 throw new RuntimeException(ex.getMessage());
756 * An instance of <code>LoggingPermission("control")</code>
757 * that is shared between calls to <code>checkAccess()</code>.
759 private static final LoggingPermission controlPermission = new LoggingPermission("control",
760 null);
763 * Checks whether the current security context allows changing
764 * the configuration of the logging framework. For the security
765 * context to be trusted, it has to be granted
766 * a LoggingPermission("control").
768 * @throws SecurityException if a security manager exists and
769 * the caller is not granted the permission to control
770 * the logging infrastructure.
772 public void checkAccess() throws SecurityException
774 SecurityManager sm = System.getSecurityManager();
775 if (sm != null)
776 sm.checkPermission(controlPermission);
780 * Creates a new instance of a class specified by name.
782 * @param className the name of the class of which a new instance
783 * should be created.
785 * @param ofClass the class to which the new instance should
786 * be either an instance or an instance of a subclass.
787 * FIXME: This description is just terrible.
789 * @return the new instance, or <code>null</code> if
790 * <code>className</code> is <code>null</code>, if no class
791 * with that name could be found, if there was an error
792 * loading that class, or if the constructor of the class
793 * has thrown an exception.
795 static final Object createInstance(String className, Class ofClass)
797 Class klass;
799 if ((className == null) || (className.length() == 0))
800 return null;
804 klass = Class.forName(className);
805 if (! ofClass.isAssignableFrom(klass))
806 return null;
808 return klass.newInstance();
810 catch (Exception _)
812 return null;
814 catch (java.lang.LinkageError _)
816 return null;