History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/logging/LogManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/util/logging/LogManager.java+1225−0
@@ -0,0 +1,1225 @@
1+/*
2+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+
27+package java.util.logging;
28+
29+import java.io.*;
30+import java.util.*;
31+import java.security.*;
32+import java.lang.ref.ReferenceQueue;
33+import java.lang.ref.WeakReference;
34+import java.beans.PropertyChangeListener;
35+import java.beans.PropertyChangeSupport;
36+import java.net.URL;
37+import sun.security.action.GetPropertyAction;
38+
39+/**
40+ * There is a single global LogManager object that is used to
41+ * maintain a set of shared state about Loggers and log services.
42+ * <p>
43+ * This LogManager object:
44+ * <ul>
45+ * <li> Manages a hierarchical namespace of Logger objects. All
46+ * named Loggers are stored in this namespace.
47+ * <li> Manages a set of logging control properties. These are
48+ * simple key-value pairs that can be used by Handlers and
49+ * other logging objects to configure themselves.
50+ * </ul>
51+ * <p>
52+ * The global LogManager object can be retrieved using LogManager.getLogManager().
53+ * The LogManager object is created during class initialization and
54+ * cannot subsequently be changed.
55+ * <p>
56+ * At startup the LogManager class is located using the
57+ * java.util.logging.manager system property.
58+ * <p>
59+ * By default, the LogManager reads its initial configuration from
60+ * a properties file "lib/logging.properties" in the JRE directory.
61+ * If you edit that property file you can change the default logging
62+ * configuration for all uses of that JRE.
63+ * <p>
64+ * In addition, the LogManager uses two optional system properties that
65+ * allow more control over reading the initial configuration:
66+ * <ul>
67+ * <li>"java.util.logging.config.class"
68+ * <li>"java.util.logging.config.file"
69+ * </ul>
70+ * These two properties may be set via the Preferences API, or as
71+ * command line property definitions to the "java" command, or as
72+ * system property definitions passed to JNI_CreateJavaVM.
73+ * <p>
74+ * If the "java.util.logging.config.class" property is set, then the
75+ * property value is treated as a class name. The given class will be
76+ * loaded, an object will be instantiated, and that object's constructor
77+ * is responsible for reading in the initial configuration. (That object
78+ * may use other system properties to control its configuration.) The
79+ * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
80+ * to define properties in the LogManager.
81+ * <p>
82+ * If "java.util.logging.config.class" property is <b>not</b> set,
83+ * then the "java.util.logging.config.file" system property can be used
84+ * to specify a properties file (in java.util.Properties format). The
85+ * initial logging configuration will be read from this file.
86+ * <p>
87+ * If neither of these properties is defined then, as described
88+ * above, the LogManager will read its initial configuration from
89+ * a properties file "lib/logging.properties" in the JRE directory.
90+ * <p>
91+ * The properties for loggers and Handlers will have names starting
92+ * with the dot-separated name for the handler or logger.
93+ * <p>
94+ * The global logging properties may include:
95+ * <ul>
96+ * <li>A property "handlers". This defines a whitespace or comma separated
97+ * list of class names for handler classes to load and register as
98+ * handlers on the root Logger (the Logger named ""). Each class
99+ * name must be for a Handler class which has a default constructor.
100+ * Note that these Handlers may be created lazily, when they are
101+ * first used.
102+ *
103+ * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
104+ * comma separated list of class names for handlers classes to
105+ * load and register as handlers to the specified logger. Each class
106+ * name must be for a Handler class which has a default constructor.
107+ * Note that these Handlers may be created lazily, when they are
108+ * first used.
109+ *
110+ * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
111+ * value. By default every logger calls its parent in addition to
112+ * handling the logging message itself, this often result in messages
113+ * being handled by the root logger as well. When setting this property
114+ * to false a Handler needs to be configured for this logger otherwise
115+ * no logging messages are delivered.
116+ *
117+ * <li>A property "config". This property is intended to allow
118+ * arbitrary configuration code to be run. The property defines a
119+ * whitespace or comma separated list of class names. A new instance will be
120+ * created for each named class. The default constructor of each class
121+ * may execute arbitrary code to update the logging configuration, such as
122+ * setting logger levels, adding handlers, adding filters, etc.
123+ * </ul>
124+ * <p>
125+ * Note that all classes loaded during LogManager configuration are
126+ * first searched on the system class path before any user class path.
127+ * That includes the LogManager class, any config classes, and any
128+ * handler classes.
129+ * <p>
130+ * Loggers are organized into a naming hierarchy based on their
131+ * dot separated names. Thus "a.b.c" is a child of "a.b", but
132+ * "a.b1" and a.b2" are peers.
133+ * <p>
134+ * All properties whose names end with ".level" are assumed to define
135+ * log levels for Loggers. Thus "foo.level" defines a log level for
136+ * the logger called "foo" and (recursively) for any of its children
137+ * in the naming hierarchy. Log Levels are applied in the order they
138+ * are defined in the properties file. Thus level settings for child
139+ * nodes in the tree should come after settings for their parents.
140+ * The property name ".level" can be used to set the level for the
141+ * root of the tree.
142+ * <p>
143+ * All methods on the LogManager object are multi-thread safe.
144+ *
145+ * @since 1.4
146+*/
147+
148+public class LogManager {
149+ // The global LogManager object
150+ private static LogManager manager;
151+
152+ private final static Handler[] emptyHandlers = { };
153+ private Properties props = new Properties();
154+ private PropertyChangeSupport changes
155+ = new PropertyChangeSupport(LogManager.class);
156+ private final static Level defaultLevel = Level.INFO;
157+
158+ // Table of named Loggers that maps names to Loggers.
159+ private Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
160+ // Tree of named Loggers
161+ private LogNode root = new LogNode(null);
162+ private Logger rootLogger;
163+
164+ // Have we done the primordial reading of the configuration file?
165+ // (Must be done after a suitable amount of java.lang.System
166+ // initialization has been done)
167+ private volatile boolean readPrimordialConfiguration;
168+ // Have we initialized global (root) handlers yet?
169+ // This gets set to false in readConfiguration
170+ private boolean initializedGlobalHandlers = true;
171+ // True if JVM death is imminent and the exit hook has been called.
172+ private boolean deathImminent;
173+
174+ static {
175+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
176+ public Object run() {
177+ String cname = null;
178+ try {
179+ cname = System.getProperty("java.util.logging.manager");
180+ if (cname != null) {
181+ try {
182+ Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
183+ manager = (LogManager) clz.newInstance();
184+ } catch (ClassNotFoundException ex) {
185+ Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
186+ manager = (LogManager) clz.newInstance();
187+ }
188+ }
189+ } catch (Exception ex) {
190+ System.err.println("Could not load Logmanager \"" + cname + "\"");
191+ ex.printStackTrace();
192+ }
193+ if (manager == null) {
194+ manager = new LogManager();
195+ }
196+
197+ // Create and retain Logger for the root of the namespace.
198+ manager.rootLogger = manager.new RootLogger();
199+ manager.addLogger(manager.rootLogger);
200+
201+ // Adding the global Logger. Doing so in the Logger.<clinit>
202+ // would deadlock with the LogManager.<clinit>.
203+ Logger.global.setLogManager(manager);
204+ manager.addLogger(Logger.global);
205+
206+ // We don't call readConfiguration() here, as we may be running
207+ // very early in the JVM startup sequence. Instead readConfiguration
208+ // will be called lazily in getLogManager().
209+ return null;
210+ }
211+ });
212+ }
213+
214+
215+ // This private class is used as a shutdown hook.
216+ // It does a "reset" to close all open handlers.
217+ private class Cleaner extends Thread {
218+
219+ private Cleaner() {
220+ /* Set context class loader to null in order to avoid
221+ * keeping a strong reference to an application classloader.
222+ */
223+ this.setContextClassLoader(null);
224+ }
225+
226+ public void run() {
227+ // This is to ensure the LogManager.<clinit> is completed
228+ // before synchronized block. Otherwise deadlocks are possible.
229+ LogManager mgr = manager;
230+
231+ // If the global handlers haven't been initialized yet, we
232+ // don't want to initialize them just so we can close them!
233+ synchronized (LogManager.this) {
234+ // Note that death is imminent.
235+ deathImminent = true;
236+ initializedGlobalHandlers = true;
237+ }
238+
239+ // Do a reset to close all active handlers.
240+ reset();
241+ }
242+ }
243+
244+
245+ /**
246+ * Protected constructor. This is protected so that container applications
247+ * (such as J2EE containers) can subclass the object. It is non-public as
248+ * it is intended that there only be one LogManager object, whose value is
249+ * retrieved by calling Logmanager.getLogManager.
250+ */
251+ protected LogManager() {
252+ // Add a shutdown hook to close the global handlers.
253+ try {
254+ Runtime.getRuntime().addShutdownHook(new Cleaner());
255+ } catch (IllegalStateException e) {
256+ // If the VM is already shutting down,
257+ // We do not need to register shutdownHook.
258+ }
259+ }
260+
261+ /**
262+ * Return the global LogManager object.
263+ */
264+ public static LogManager getLogManager() {
265+ if (manager != null) {
266+ manager.readPrimordialConfiguration();
267+ }
268+ return manager;
269+ }
270+
271+ private void readPrimordialConfiguration() {
272+ if (!readPrimordialConfiguration) {
273+ synchronized (this) {
274+ if (!readPrimordialConfiguration) {
275+ // If System.in/out/err are null, it's a good
276+ // indication that we're still in the
277+ // bootstrapping phase
278+ if (System.out == null) {
279+ return;
280+ }
281+ readPrimordialConfiguration = true;
282+ try {
283+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
284+ public Object run() throws Exception {
285+ readConfiguration();
286+
287+ // Platform loggers begin to delegate to java.util.logging.Logger
288+ sun.util.logging.PlatformLogger.redirectPlatformLoggers();
289+
290+ return null;
291+ }
292+ });
293+ } catch (Exception ex) {
294+ // System.err.println("Can't read logging configuration:");
295+ // ex.printStackTrace();
296+ }
297+ }
298+ }
299+ }
300+ }
301+
302+ /**
303+ * Adds an event listener to be invoked when the logging
304+ * properties are re-read. Adding multiple instances of
305+ * the same event Listener results in multiple entries
306+ * in the property event listener table.
307+ *
308+ * @param l event listener
309+ * @exception SecurityException if a security manager exists and if
310+ * the caller does not have LoggingPermission("control").
311+ * @exception NullPointerException if the PropertyChangeListener is null.
312+ */
313+ public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException {
314+ if (l == null) {
315+ throw new NullPointerException();
316+ }
317+ checkAccess();
318+ changes.addPropertyChangeListener(l);
319+ }
320+
321+ /**
322+ * Removes an event listener for property change events.
323+ * If the same listener instance has been added to the listener table
324+ * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
325+ * then an equivalent number of
326+ * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
327+ * all instances of that listener from the listener table.
328+ * <P>
329+ * Returns silently if the given listener is not found.
330+ *
331+ * @param l event listener (can be null)
332+ * @exception SecurityException if a security manager exists and if
333+ * the caller does not have LoggingPermission("control").
334+ */
335+ public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException {
336+ checkAccess();
337+ changes.removePropertyChangeListener(l);
338+ }
339+
340+ // Package-level method.
341+ // Find or create a specified logger instance. If a logger has
342+ // already been created with the given name it is returned.
343+ // Otherwise a new logger instance is created and registered
344+ // in the LogManager global namespace.
345+
346+ // This method will always return a non-null Logger object.
347+ // Synchronization is not required here. All synchronization for
348+ // adding a new Logger object is handled by addLogger().
349+ Logger demandLogger(String name) {
350+ Logger result = getLogger(name);
351+ if (result == null) {
352+ // only allocate the new logger once
353+ Logger newLogger = new Logger(name, null);
354+ do {
355+ if (addLogger(newLogger)) {
356+ // We successfully added the new Logger that we
357+ // created above so return it without refetching.
358+ return newLogger;
359+ }
360+
361+ // We didn't add the new Logger that we created above
362+ // because another thread added a Logger with the same
363+ // name after our null check above and before our call
364+ // to addLogger(). We have to refetch the Logger because
365+ // addLogger() returns a boolean instead of the Logger
366+ // reference itself. However, if the thread that created
367+ // the other Logger is not holding a strong reference to
368+ // the other Logger, then it is possible for the other
369+ // Logger to be GC'ed after we saw it in addLogger() and
370+ // before we can refetch it. If it has been GC'ed then
371+ // we'll just loop around and try again.
372+ result = getLogger(name);
373+ } while (result == null);
374+ }
375+ return result;
376+ }
377+
378+ // If logger.getUseParentHandlers() returns 'true' and any of the logger's
379+ // parents have levels or handlers defined, make sure they are instantiated.
380+ private void processParentHandlers(Logger logger, String name) {
381+ int ix = 1;
382+ for (;;) {
383+ int ix2 = name.indexOf(".", ix);
384+ if (ix2 < 0) {
385+ break;
386+ }
387+ String pname = name.substring(0,ix2);
388+
389+ if (getProperty(pname+".level") != null ||
390+ getProperty(pname+".handlers") != null) {
391+ // This pname has a level/handlers definition.
392+ // Make sure it exists.
393+ demandLogger(pname);
394+ }
395+ ix = ix2+1;
396+ }
397+ }
398+
399+ // Add new per logger handlers.
400+ // We need to raise privilege here. All our decisions will
401+ // be made based on the logging configuration, which can
402+ // only be modified by trusted code.
403+ private void loadLoggerHandlers(final Logger logger, final String name,
404+ final String handlersPropertyName) {
405+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
406+ public Object run() {
407+ if (logger != rootLogger) {
408+ boolean useParent = getBooleanProperty(name + ".useParentHandlers", true);
409+ if (!useParent) {
410+ logger.setUseParentHandlers(false);
411+ }
412+ }
413+
414+ String names[] = parseClassNames(handlersPropertyName);
415+ for (int i = 0; i < names.length; i++) {
416+ String word = names[i];
417+ try {
418+ Class clz = ClassLoader.getSystemClassLoader().loadClass(word);
419+ Handler hdl = (Handler) clz.newInstance();
420+ try {
421+ // Check if there is a property defining the
422+ // this handler's level.
423+ String levs = getProperty(word + ".level");
424+ if (levs != null) {
425+ hdl.setLevel(Level.parse(levs));
426+ }
427+ } catch (Exception ex) {
428+ System.err.println("Can't set level for " + word);
429+ // Probably a bad level. Drop through.
430+ }
431+ // Add this Handler to the logger
432+ logger.addHandler(hdl);
433+ } catch (Exception ex) {
434+ System.err.println("Can't load log handler \"" + word + "\"");
435+ System.err.println("" + ex);
436+ ex.printStackTrace();
437+ }
438+ }
439+ return null;
440+ }});
441+ }
442+
443+
444+ // loggerRefQueue holds LoggerWeakRef objects for Logger objects
445+ // that have been GC'ed.
446+ private final ReferenceQueue<Logger> loggerRefQueue
447+ = new ReferenceQueue<>();
448+
449+ // Package-level inner class.
450+ // Helper class for managing WeakReferences to Logger objects.
451+ //
452+ // LogManager.namedLoggers
453+ // - has weak references to all named Loggers
454+ // - namedLoggers keeps the LoggerWeakRef objects for the named
455+ // Loggers around until we can deal with the book keeping for
456+ // the named Logger that is being GC'ed.
457+ // LogManager.LogNode.loggerRef
458+ // - has a weak reference to a named Logger
459+ // - the LogNode will also keep the LoggerWeakRef objects for
460+ // the named Loggers around; currently LogNodes never go away.
461+ // Logger.kids
462+ // - has a weak reference to each direct child Logger; this
463+ // includes anonymous and named Loggers
464+ // - anonymous Loggers are always children of the rootLogger
465+ // which is a strong reference; rootLogger.kids keeps the
466+ // LoggerWeakRef objects for the anonymous Loggers around
467+ // until we can deal with the book keeping.
468+ //
469+ final class LoggerWeakRef extends WeakReference<Logger> {
470+ private String name; // for namedLoggers cleanup
471+ private LogNode node; // for loggerRef cleanup
472+ private WeakReference<Logger> parentRef; // for kids cleanup
473+
474+ LoggerWeakRef(Logger logger) {
475+ super(logger, loggerRefQueue);
476+
477+ name = logger.getName(); // save for namedLoggers cleanup
478+ }
479+
480+ // dispose of this LoggerWeakRef object
481+ void dispose() {
482+ if (node != null) {
483+ // if we have a LogNode, then we were a named Logger
484+ // so clear namedLoggers weak ref to us
485+ manager.namedLoggers.remove(name);
486+ name = null; // clear our ref to the Logger's name
487+
488+ node.loggerRef = null; // clear LogNode's weak ref to us
489+ node = null; // clear our ref to LogNode
490+ }
491+
492+ if (parentRef != null) {
493+ // this LoggerWeakRef has or had a parent Logger
494+ Logger parent = parentRef.get();
495+ if (parent != null) {
496+ // the parent Logger is still there so clear the
497+ // parent Logger's weak ref to us
498+ parent.removeChildLogger(this);
499+ }
500+ parentRef = null; // clear our weak ref to the parent Logger
501+ }
502+ }
503+
504+ // set the node field to the specified value
505+ void setNode(LogNode node) {
506+ this.node = node;
507+ }
508+
509+ // set the parentRef field to the specified value
510+ void setParentRef(WeakReference<Logger> parentRef) {
511+ this.parentRef = parentRef;
512+ }
513+ }
514+
515+ // Package-level method.
516+ // Drain some Logger objects that have been GC'ed.
517+ //
518+ // drainLoggerRefQueueBounded() is called by addLogger() below
519+ // and by Logger.getAnonymousLogger(String) so we'll drain up to
520+ // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
521+ //
522+ // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
523+ // us about a 50/50 mix in increased weak ref counts versus
524+ // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
525+ // Here are stats for cleaning up sets of 400 anonymous Loggers:
526+ // - test duration 1 minute
527+ // - sample size of 125 sets of 400
528+ // - average: 1.99 ms
529+ // - minimum: 0.57 ms
530+ // - maximum: 25.3 ms
531+ //
532+ // The same config gives us a better decreased weak ref count
533+ // than increased weak ref count in the LoggerWeakRefLeak test.
534+ // Here are stats for cleaning up sets of 400 named Loggers:
535+ // - test duration 2 minutes
536+ // - sample size of 506 sets of 400
537+ // - average: 0.57 ms
538+ // - minimum: 0.02 ms
539+ // - maximum: 10.9 ms
540+ //
541+ private final static int MAX_ITERATIONS = 400;
542+ final synchronized void drainLoggerRefQueueBounded() {
543+ for (int i = 0; i < MAX_ITERATIONS; i++) {
544+ if (loggerRefQueue == null) {
545+ // haven't finished loading LogManager yet
546+ break;
547+ }
548+
549+ LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
550+ if (ref == null) {
551+ break;
552+ }
553+ // a Logger object has been GC'ed so clean it up
554+ ref.dispose();
555+ }
556+ }
557+
558+ /**
559+ * Add a named logger. This does nothing and returns false if a logger
560+ * with the same name is already registered.
561+ * <p>
562+ * The Logger factory methods call this method to register each
563+ * newly created Logger.
564+ * <p>
565+ * The application should retain its own reference to the Logger
566+ * object to avoid it being garbage collected. The LogManager
567+ * may only retain a weak reference.
568+ *
569+ * @param logger the new logger.
570+ * @return true if the argument logger was registered successfully,
571+ * false if a logger of that name already exists.
572+ * @exception NullPointerException if the logger name is null.
573+ */
574+ public synchronized boolean addLogger(Logger logger) {
575+ final String name = logger.getName();
576+ if (name == null) {
577+ throw new NullPointerException();
578+ }
579+
580+ // cleanup some Loggers that have been GC'ed
581+ drainLoggerRefQueueBounded();
582+
583+ LoggerWeakRef ref = namedLoggers.get(name);
584+ if (ref != null) {
585+ if (ref.get() == null) {
586+ // It's possible that the Logger was GC'ed after the
587+ // drainLoggerRefQueueBounded() call above so allow
588+ // a new one to be registered.
589+ namedLoggers.remove(name);
590+ } else {
591+ // We already have a registered logger with the given name.
592+ return false;
593+ }
594+ }
595+
596+ // We're adding a new logger.
597+ // Note that we are creating a weak reference here.
598+ ref = new LoggerWeakRef(logger);
599+ namedLoggers.put(name, ref);
600+
601+ // Apply any initial level defined for the new logger.
602+ Level level = getLevelProperty(name+".level", null);
603+ if (level != null) {
604+ doSetLevel(logger, level);
605+ }
606+
607+ // Do we have a per logger handler too?
608+ // Note: this will add a 200ms penalty
609+ loadLoggerHandlers(logger, name, name+".handlers");
610+ processParentHandlers(logger, name);
611+
612+ // Find the new node and its parent.
613+ LogNode node = findNode(name);
614+ node.loggerRef = ref;
615+ Logger parent = null;
616+ LogNode nodep = node.parent;
617+ while (nodep != null) {
618+ LoggerWeakRef nodeRef = nodep.loggerRef;
619+ if (nodeRef != null) {
620+ parent = nodeRef.get();
621+ if (parent != null) {
622+ break;
623+ }
624+ }
625+ nodep = nodep.parent;
626+ }
627+
628+ if (parent != null) {
629+ doSetParent(logger, parent);
630+ }
631+ // Walk over the children and tell them we are their new parent.
632+ node.walkAndSetParent(logger);
633+
634+ // new LogNode is ready so tell the LoggerWeakRef about it
635+ ref.setNode(node);
636+
637+ return true;
638+ }
639+
640+
641+ // Private method to set a level on a logger.
642+ // If necessary, we raise privilege before doing the call.
643+ private static void doSetLevel(final Logger logger, final Level level) {
644+ SecurityManager sm = System.getSecurityManager();
645+ if (sm == null) {
646+ // There is no security manager, so things are easy.
647+ logger.setLevel(level);
648+ return;
649+ }
650+ // There is a security manager. Raise privilege before
651+ // calling setLevel.
652+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
653+ public Object run() {
654+ logger.setLevel(level);
655+ return null;
656+ }});
657+ }
658+
659+
660+
661+ // Private method to set a parent on a logger.
662+ // If necessary, we raise privilege before doing the setParent call.
663+ private static void doSetParent(final Logger logger, final Logger parent) {
664+ SecurityManager sm = System.getSecurityManager();
665+ if (sm == null) {
666+ // There is no security manager, so things are easy.
667+ logger.setParent(parent);
668+ return;
669+ }
670+ // There is a security manager. Raise privilege before
671+ // calling setParent.
672+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
673+ public Object run() {
674+ logger.setParent(parent);
675+ return null;
676+ }});
677+ }
678+
679+ // Find a node in our tree of logger nodes.
680+ // If necessary, create it.
681+ private LogNode findNode(String name) {
682+ if (name == null || name.equals("")) {
683+ return root;
684+ }
685+ LogNode node = root;
686+ while (name.length() > 0) {
687+ int ix = name.indexOf(".");
688+ String head;
689+ if (ix > 0) {
690+ head = name.substring(0,ix);
691+ name = name.substring(ix+1);
692+ } else {
693+ head = name;
694+ name = "";
695+ }
696+ if (node.children == null) {
697+ node.children = new HashMap<>();
698+ }
699+ LogNode child = node.children.get(head);
700+ if (child == null) {
701+ child = new LogNode(node);
702+ node.children.put(head, child);
703+ }
704+ node = child;
705+ }
706+ return node;
707+ }
708+
709+ /**
710+ * Method to find a named logger.
711+ * <p>
712+ * Note that since untrusted code may create loggers with
713+ * arbitrary names this method should not be relied on to
714+ * find Loggers for security sensitive logging.
715+ * It is also important to note that the Logger associated with the
716+ * String {@code name} may be garbage collected at any time if there
717+ * is no strong reference to the Logger. The caller of this method
718+ * must check the return value for null in order to properly handle
719+ * the case where the Logger has been garbage collected.
720+ * <p>
721+ * @param name name of the logger
722+ * @return matching logger or null if none is found
723+ */
724+ public synchronized Logger getLogger(String name) {
725+ LoggerWeakRef ref = namedLoggers.get(name);
726+ if (ref == null) {
727+ return null;
728+ }
729+ Logger logger = ref.get();
730+ if (logger == null) {
731+ // Hashtable holds stale weak reference
732+ // to a logger which has been GC-ed.
733+ namedLoggers.remove(name);
734+ }
735+ return logger;
736+ }
737+
738+ /**
739+ * Get an enumeration of known logger names.
740+ * <p>
741+ * Note: Loggers may be added dynamically as new classes are loaded.
742+ * This method only reports on the loggers that are currently registered.
743+ * It is also important to note that this method only returns the name
744+ * of a Logger, not a strong reference to the Logger itself.
745+ * The returned String does nothing to prevent the Logger from being
746+ * garbage collected. In particular, if the returned name is passed
747+ * to {@code LogManager.getLogger()}, then the caller must check the
748+ * return value from {@code LogManager.getLogger()} for null to properly
749+ * handle the case where the Logger has been garbage collected in the
750+ * time since its name was returned by this method.
751+ * <p>
752+ * @return enumeration of logger name strings
753+ */
754+ public synchronized Enumeration<String> getLoggerNames() {
755+ return namedLoggers.keys();
756+ }
757+
758+ /**
759+ * Reinitialize the logging properties and reread the logging configuration.
760+ * <p>
761+ * The same rules are used for locating the configuration properties
762+ * as are used at startup. So normally the logging properties will
763+ * be re-read from the same file that was used at startup.
764+ * <P>
765+ * Any log level definitions in the new configuration file will be
766+ * applied using Logger.setLevel(), if the target Logger exists.
767+ * <p>
768+ * A PropertyChangeEvent will be fired after the properties are read.
769+ *
770+ * @exception SecurityException if a security manager exists and if
771+ * the caller does not have LoggingPermission("control").
772+ * @exception IOException if there are IO problems reading the configuration.
773+ */
774+ public void readConfiguration() throws IOException, SecurityException {
775+ checkAccess();
776+
777+ // if a configuration class is specified, load it and use it.
778+ String cname = System.getProperty("java.util.logging.config.class");
779+ if (cname != null) {
780+ try {
781+ // Instantiate the named class. It is its constructor's
782+ // responsibility to initialize the logging configuration, by
783+ // calling readConfiguration(InputStream) with a suitable stream.
784+ try {
785+ Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
786+ clz.newInstance();
787+ return;
788+ } catch (ClassNotFoundException ex) {
789+ Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
790+ clz.newInstance();
791+ return;
792+ }
793+ } catch (Exception ex) {
794+ System.err.println("Logging configuration class \"" + cname + "\" failed");
795+ System.err.println("" + ex);
796+ // keep going and useful config file.
797+ }
798+ }
799+
800+ String fname = System.getProperty("java.util.logging.config.file");
801+ if (fname == null) {
802+ fname = System.getProperty("java.home");
803+ if (fname == null) {
804+ throw new Error("Can't find java.home ??");
805+ }
806+ File f = new File(fname, "lib");
807+ f = new File(f, "logging.properties");
808+ fname = f.getCanonicalPath();
809+ }
810+ InputStream in = new FileInputStream(fname);
811+ BufferedInputStream bin = new BufferedInputStream(in);
812+ try {
813+ readConfiguration(bin);
814+ } finally {
815+ if (in != null) {
816+ in.close();
817+ }
818+ }
819+ }
820+
821+ /**
822+ * Reset the logging configuration.
823+ * <p>
824+ * For all named loggers, the reset operation removes and closes
825+ * all Handlers and (except for the root logger) sets the level
826+ * to null. The root logger's level is set to Level.INFO.
827+ *
828+ * @exception SecurityException if a security manager exists and if
829+ * the caller does not have LoggingPermission("control").
830+ */
831+
832+ public void reset() throws SecurityException {
833+ checkAccess();
834+ synchronized (this) {
835+ props = new Properties();
836+ // Since we are doing a reset we no longer want to initialize
837+ // the global handlers, if they haven't been initialized yet.
838+ initializedGlobalHandlers = true;
839+ }
840+ Enumeration enum_ = getLoggerNames();
841+ while (enum_.hasMoreElements()) {
842+ String name = (String)enum_.nextElement();
843+ resetLogger(name);
844+ }
845+ }
846+
847+
848+ // Private method to reset an individual target logger.
849+ private void resetLogger(String name) {
850+ Logger logger = getLogger(name);
851+ if (logger == null) {
852+ return;
853+ }
854+ // Close all the Logger's handlers.
855+ Handler[] targets = logger.getHandlers();
856+ for (int i = 0; i < targets.length; i++) {
857+ Handler h = targets[i];
858+ logger.removeHandler(h);
859+ try {
860+ h.close();
861+ } catch (Exception ex) {
862+ // Problems closing a handler? Keep going...
863+ }
864+ }
865+ if (name != null && name.equals("")) {
866+ // This is the root logger.
867+ logger.setLevel(defaultLevel);
868+ } else {
869+ logger.setLevel(null);
870+ }
871+ }
872+
873+ // get a list of whitespace separated classnames from a property.
874+ private String[] parseClassNames(String propertyName) {
875+ String hands = getProperty(propertyName);
876+ if (hands == null) {
877+ return new String[0];
878+ }
879+ hands = hands.trim();
880+ int ix = 0;
881+ Vector<String> result = new Vector<>();
882+ while (ix < hands.length()) {
883+ int end = ix;
884+ while (end < hands.length()) {
885+ if (Character.isWhitespace(hands.charAt(end))) {
886+ break;
887+ }
888+ if (hands.charAt(end) == ',') {
889+ break;
890+ }
891+ end++;
892+ }
893+ String word = hands.substring(ix, end);
894+ ix = end+1;
895+ word = word.trim();
896+ if (word.length() == 0) {
897+ continue;
898+ }
899+ result.add(word);
900+ }
901+ return result.toArray(new String[result.size()]);
902+ }
903+
904+ /**
905+ * Reinitialize the logging properties and reread the logging configuration
906+ * from the given stream, which should be in java.util.Properties format.
907+ * A PropertyChangeEvent will be fired after the properties are read.
908+ * <p>
909+ * Any log level definitions in the new configuration file will be
910+ * applied using Logger.setLevel(), if the target Logger exists.
911+ *
912+ * @param ins stream to read properties from
913+ * @exception SecurityException if a security manager exists and if
914+ * the caller does not have LoggingPermission("control").
915+ * @exception IOException if there are problems reading from the stream.
916+ */
917+ public void readConfiguration(InputStream ins) throws IOException, SecurityException {
918+ checkAccess();
919+ reset();
920+
921+ // Load the properties
922+ props.load(ins);
923+ // Instantiate new configuration objects.
924+ String names[] = parseClassNames("config");
925+
926+ for (int i = 0; i < names.length; i++) {
927+ String word = names[i];
928+ try {
929+ Class clz = ClassLoader.getSystemClassLoader().loadClass(word);
930+ clz.newInstance();
931+ } catch (Exception ex) {
932+ System.err.println("Can't load config class \"" + word + "\"");
933+ System.err.println("" + ex);
934+ // ex.printStackTrace();
935+ }
936+ }
937+
938+ // Set levels on any pre-existing loggers, based on the new properties.
939+ setLevelsOnExistingLoggers();
940+
941+ // Notify any interested parties that our properties have changed.
942+ changes.firePropertyChange(null, null, null);
943+
944+ // Note that we need to reinitialize global handles when
945+ // they are first referenced.
946+ synchronized (this) {
947+ initializedGlobalHandlers = false;
948+ }
949+ }
950+
951+ /**
952+ * Get the value of a logging property.
953+ * The method returns null if the property is not found.
954+ * @param name property name
955+ * @return property value
956+ */
957+ public String getProperty(String name) {
958+ return props.getProperty(name);
959+ }
960+
961+ // Package private method to get a String property.
962+ // If the property is not defined we return the given
963+ // default value.
964+ String getStringProperty(String name, String defaultValue) {
965+ String val = getProperty(name);
966+ if (val == null) {
967+ return defaultValue;
968+ }
969+ return val.trim();
970+ }
971+
972+ // Package private method to get an integer property.
973+ // If the property is not defined or cannot be parsed
974+ // we return the given default value.
975+ int getIntProperty(String name, int defaultValue) {
976+ String val = getProperty(name);
977+ if (val == null) {
978+ return defaultValue;
979+ }
980+ try {
981+ return Integer.parseInt(val.trim());
982+ } catch (Exception ex) {
983+ return defaultValue;
984+ }
985+ }
986+
987+ // Package private method to get a boolean property.
988+ // If the property is not defined or cannot be parsed
989+ // we return the given default value.
990+ boolean getBooleanProperty(String name, boolean defaultValue) {
991+ String val = getProperty(name);
992+ if (val == null) {
993+ return defaultValue;
994+ }
995+ val = val.toLowerCase();
996+ if (val.equals("true") || val.equals("1")) {
997+ return true;
998+ } else if (val.equals("false") || val.equals("0")) {
999+ return false;
1000+ }
1001+ return defaultValue;
1002+ }
1003+
1004+ // Package private method to get a Level property.
1005+ // If the property is not defined or cannot be parsed
1006+ // we return the given default value.
1007+ Level getLevelProperty(String name, Level defaultValue) {
1008+ String val = getProperty(name);
1009+ if (val == null) {
1010+ return defaultValue;
1011+ }
1012+ try {
1013+ return Level.parse(val.trim());
1014+ } catch (Exception ex) {
1015+ return defaultValue;
1016+ }
1017+ }
1018+
1019+ // Package private method to get a filter property.
1020+ // We return an instance of the class named by the "name"
1021+ // property. If the property is not defined or has problems
1022+ // we return the defaultValue.
1023+ Filter getFilterProperty(String name, Filter defaultValue) {
1024+ String val = getProperty(name);
1025+ try {
1026+ if (val != null) {
1027+ Class clz = ClassLoader.getSystemClassLoader().loadClass(val);
1028+ return (Filter) clz.newInstance();
1029+ }
1030+ } catch (Exception ex) {
1031+ // We got one of a variety of exceptions in creating the
1032+ // class or creating an instance.
1033+ // Drop through.
1034+ }
1035+ // We got an exception. Return the defaultValue.
1036+ return defaultValue;
1037+ }
1038+
1039+
1040+ // Package private method to get a formatter property.
1041+ // We return an instance of the class named by the "name"
1042+ // property. If the property is not defined or has problems
1043+ // we return the defaultValue.
1044+ Formatter getFormatterProperty(String name, Formatter defaultValue) {
1045+ String val = getProperty(name);
1046+ try {
1047+ if (val != null) {
1048+ Class clz = ClassLoader.getSystemClassLoader().loadClass(val);
1049+ return (Formatter) clz.newInstance();
1050+ }
1051+ } catch (Exception ex) {
1052+ // We got one of a variety of exceptions in creating the
1053+ // class or creating an instance.
1054+ // Drop through.
1055+ }
1056+ // We got an exception. Return the defaultValue.
1057+ return defaultValue;
1058+ }
1059+
1060+ // Private method to load the global handlers.
1061+ // We do the real work lazily, when the global handlers
1062+ // are first used.
1063+ private synchronized void initializeGlobalHandlers() {
1064+ if (initializedGlobalHandlers) {
1065+ return;
1066+ }
1067+
1068+ initializedGlobalHandlers = true;
1069+
1070+ if (deathImminent) {
1071+ // Aaargh...
1072+ // The VM is shutting down and our exit hook has been called.
1073+ // Avoid allocating global handlers.
1074+ return;
1075+ }
1076+ loadLoggerHandlers(rootLogger, null, "handlers");
1077+ }
1078+
1079+
1080+ private Permission ourPermission = new LoggingPermission("control", null);
1081+
1082+ /**
1083+ * Check that the current context is trusted to modify the logging
1084+ * configuration. This requires LoggingPermission("control").
1085+ * <p>
1086+ * If the check fails we throw a SecurityException, otherwise
1087+ * we return normally.
1088+ *
1089+ * @exception SecurityException if a security manager exists and if
1090+ * the caller does not have LoggingPermission("control").
1091+ */
1092+ public void checkAccess() throws SecurityException {
1093+ SecurityManager sm = System.getSecurityManager();
1094+ if (sm == null) {
1095+ return;
1096+ }
1097+ sm.checkPermission(ourPermission);
1098+ }
1099+
1100+ // Nested class to represent a node in our tree of named loggers.
1101+ private static class LogNode {
1102+ HashMap<String,LogNode> children;
1103+ LoggerWeakRef loggerRef;
1104+ LogNode parent;
1105+
1106+ LogNode(LogNode parent) {
1107+ this.parent = parent;
1108+ }
1109+
1110+ // Recursive method to walk the tree below a node and set
1111+ // a new parent logger.
1112+ void walkAndSetParent(Logger parent) {
1113+ if (children == null) {
1114+ return;
1115+ }
1116+ Iterator<LogNode> values = children.values().iterator();
1117+ while (values.hasNext()) {
1118+ LogNode node = values.next();
1119+ LoggerWeakRef ref = node.loggerRef;
1120+ Logger logger = (ref == null) ? null : ref.get();
1121+ if (logger == null) {
1122+ node.walkAndSetParent(parent);
1123+ } else {
1124+ doSetParent(logger, parent);
1125+ }
1126+ }
1127+ }
1128+ }
1129+
1130+ // We use a subclass of Logger for the root logger, so
1131+ // that we only instantiate the global handlers when they
1132+ // are first needed.
1133+ private class RootLogger extends Logger {
1134+
1135+ private RootLogger() {
1136+ super("", null);
1137+ setLevel(defaultLevel);
1138+ }
1139+
1140+ public void log(LogRecord record) {
1141+ // Make sure that the global handlers have been instantiated.
1142+ initializeGlobalHandlers();
1143+ super.log(record);
1144+ }
1145+
1146+ public void addHandler(Handler h) {
1147+ initializeGlobalHandlers();
1148+ super.addHandler(h);
1149+ }
1150+
1151+ public void removeHandler(Handler h) {
1152+ initializeGlobalHandlers();
1153+ super.removeHandler(h);
1154+ }
1155+
1156+ public Handler[] getHandlers() {
1157+ initializeGlobalHandlers();
1158+ return super.getHandlers();
1159+ }
1160+ }
1161+
1162+
1163+ // Private method to be called when the configuration has
1164+ // changed to apply any level settings to any pre-existing loggers.
1165+ synchronized private void setLevelsOnExistingLoggers() {
1166+ Enumeration enum_ = props.propertyNames();
1167+ while (enum_.hasMoreElements()) {
1168+ String key = (String)enum_.nextElement();
1169+ if (!key.endsWith(".level")) {
1170+ // Not a level definition.
1171+ continue;
1172+ }
1173+ int ix = key.length() - 6;
1174+ String name = key.substring(0, ix);
1175+ Level level = getLevelProperty(key, null);
1176+ if (level == null) {
1177+ System.err.println("Bad level value for property: " + key);
1178+ continue;
1179+ }
1180+ Logger l = getLogger(name);
1181+ if (l == null) {
1182+ continue;
1183+ }
1184+ l.setLevel(level);
1185+ }
1186+ }
1187+
1188+ // Management Support
1189+ private static LoggingMXBean loggingMXBean = null;
1190+ /**
1191+ * String representation of the
1192+ * {@link javax.management.ObjectName} for the management interface
1193+ * for the logging facility.
1194+ *
1195+ * @see java.lang.management.PlatformLoggingMXBean
1196+ * @see java.util.logging.LoggingMXBean
1197+ *
1198+ * @since 1.5
1199+ */
1200+ public final static String LOGGING_MXBEAN_NAME
1201+ = "java.util.logging:type=Logging";
1202+
1203+ /**
1204+ * Returns <tt>LoggingMXBean</tt> for managing loggers.
1205+ * An alternative way to manage loggers is through the
1206+ * {@link java.lang.management.PlatformLoggingMXBean} interface
1207+ * that can be obtained by calling:
1208+ * <pre>
1209+ * PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
1210+ * ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class);
1211+ * </pre>
1212+ *
1213+ * @return a {@link LoggingMXBean} object.
1214+ *
1215+ * @see java.lang.management.PlatformLoggingMXBean
1216+ * @since 1.5
1217+ */
1218+ public static synchronized LoggingMXBean getLoggingMXBean() {
1219+ if (loggingMXBean == null) {
1220+ loggingMXBean = new Logging();
1221+ }
1222+ return loggingMXBean;
1223+ }
1224+
1225+}