< prev index next >

src/java.logging/share/classes/java/util/logging/LogManager.java

Print this page




  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.util.concurrent.ConcurrentHashMap;
  35 import java.util.concurrent.CopyOnWriteArrayList;

  36 import sun.misc.JavaAWTAccess;
  37 import sun.misc.ManagedLocalsThread;
  38 import sun.misc.SharedSecrets;
  39 
  40 /**
  41  * There is a single global LogManager object that is used to
  42  * maintain a set of shared state about Loggers and log services.
  43  * <p>
  44  * This LogManager object:
  45  * <ul>
  46  * <li> Manages a hierarchical namespace of Logger objects.  All
  47  *      named Loggers are stored in this namespace.
  48  * <li> Manages a set of logging control properties.  These are
  49  *      simple key-value pairs that can be used by Handlers and
  50  *      other logging objects to configure themselves.
  51  * </ul>
  52  * <p>
  53  * The global LogManager object can be retrieved using LogManager.getLogManager().
  54  * The LogManager object is created during class initialization and
  55  * cannot subsequently be changed.
  56  * <p>
  57  * At startup the LogManager class is located using the


 163     // be able to see a partially constructed 'props' object.
 164     // (seeing a partially constructed 'props' object can result in
 165     // NPE being thrown in Hashtable.get(), because it leaves the door
 166     // open for props.getProperties() to be called before the construcor
 167     // of Hashtable is actually completed).
 168     private volatile Properties props = new Properties();
 169     private final static Level defaultLevel = Level.INFO;
 170 
 171     // LoggerContext for system loggers and user loggers
 172     private final LoggerContext systemContext = new SystemLoggerContext();
 173     private final LoggerContext userContext = new LoggerContext();
 174     // non final field - make it volatile to make sure that other threads
 175     // will see the new value once ensureLogManagerInitialized() has finished
 176     // executing.
 177     private volatile Logger rootLogger;
 178     // Have we done the primordial reading of the configuration file?
 179     // (Must be done after a suitable amount of java.lang.System
 180     // initialization has been done)
 181     private volatile boolean readPrimordialConfiguration;
 182     // Have we initialized global (root) handlers yet?
 183     // This gets set to false in readConfiguration
 184     private boolean initializedGlobalHandlers = true;
 185     // True if JVM death is imminent and the exit hook has been called.
 186     private boolean deathImminent;





 187 
 188     // This list contains the loggers for which some handlers have been
 189     // explicitly configured in the configuration file.
 190     // It prevents these loggers from being arbitrarily garbage collected.
 191     private static final class CloseOnReset {
 192         private final Logger logger;
 193         private CloseOnReset(Logger ref) {
 194             this.logger = Objects.requireNonNull(ref);
 195         }
 196         @Override
 197         public boolean equals(Object other) {
 198             return (other instanceof CloseOnReset) && ((CloseOnReset)other).logger == logger;
 199         }
 200         @Override
 201         public int hashCode() {
 202             return System.identityHashCode(logger);
 203         }
 204         public Logger get() {
 205             return logger;
 206         }


 232                             Class<?> clz = Thread.currentThread()
 233                                     .getContextClassLoader().loadClass(cname);
 234                             mgr = (LogManager) clz.newInstance();
 235                         }
 236                     }
 237                 } catch (Exception ex) {
 238                     System.err.println("Could not load Logmanager \"" + cname + "\"");
 239                     ex.printStackTrace();
 240                 }
 241                 if (mgr == null) {
 242                     mgr = new LogManager();
 243                 }
 244                 return mgr;
 245 
 246             }
 247         });
 248     }
 249 
 250     // This private class is used as a shutdown hook.
 251     // It does a "reset" to close all open handlers.
 252     private class Cleaner extends ManagedLocalsThread {
 253 
 254         private Cleaner() {
 255             /* Set context class loader to null in order to avoid
 256              * keeping a strong reference to an application classloader.
 257              */
 258             this.setContextClassLoader(null);
 259         }
 260 
 261         @Override
 262         public void run() {
 263             // This is to ensure the LogManager.<clinit> is completed
 264             // before synchronized block. Otherwise deadlocks are possible.
 265             LogManager mgr = manager;
 266 
 267             // If the global handlers haven't been initialized yet, we
 268             // don't want to initialize them just so we can close them!
 269             synchronized (LogManager.this) {
 270                 // Note that death is imminent.
 271                 deathImminent = true;
 272                 initializedGlobalHandlers = true;
 273             }
 274 
 275             // Do a reset to close all active handlers.
 276             reset();






 277         }
 278     }
 279 
 280 
 281     /**
 282      * Protected constructor.  This is protected so that container applications
 283      * (such as J2EE containers) can subclass the object.  It is non-public as
 284      * it is intended that there only be one LogManager object, whose value is
 285      * retrieved by calling LogManager.getLogManager.
 286      */
 287     protected LogManager() {
 288         this(checkSubclassPermissions());
 289     }
 290 
 291     private LogManager(Void checked) {
 292 
 293         // Add a shutdown hook to close the global handlers.
 294         try {
 295             Runtime.getRuntime().addShutdownHook(new Cleaner());
 296         } catch (IllegalStateException e) {


1297         }
1298         try (final InputStream in = new FileInputStream(fname)) {
1299             final BufferedInputStream bin = new BufferedInputStream(in);
1300             readConfiguration(bin);
1301         }
1302     }
1303 
1304     /**
1305      * Reset the logging configuration.
1306      * <p>
1307      * For all named loggers, the reset operation removes and closes
1308      * all Handlers and (except for the root logger) sets the level
1309      * to null.  The root logger's level is set to Level.INFO.
1310      *
1311      * @exception  SecurityException  if a security manager exists and if
1312      *             the caller does not have LoggingPermission("control").
1313      */
1314 
1315     public void reset() throws SecurityException {
1316         checkPermission();

1317         List<CloseOnReset> persistent;
1318         synchronized (this) {









1319             props = new Properties();
1320             // make sure we keep the loggers persistent until reset is done.
1321             // Those are the loggers for which we previously created a
1322             // handler from the configuration, and we need to prevent them
1323             // from being gc'ed until those handlers are closed.
1324             persistent = new ArrayList<>(closeOnResetLoggers);
1325             closeOnResetLoggers.clear();

1326             // Since we are doing a reset we no longer want to initialize
1327             // the global handlers, if they haven't been initialized yet.
1328             initializedGlobalHandlers = true;




1329         }

1330         for (LoggerContext cx : contexts()) {










1331             Enumeration<String> enum_ = cx.getLoggerNames();
1332             while (enum_.hasMoreElements()) {
1333                 String name = enum_.nextElement();
1334                 Logger logger = cx.findLogger(name);
1335                 if (logger != null) {
1336                     resetLogger(logger);
1337                 }
1338             }
1339         }
1340         persistent.clear();
1341     }
1342 
1343     // Private method to reset an individual target logger.
1344     private void resetLogger(Logger logger) {
1345         // Close all the Logger's handlers.
1346         Handler[] targets = logger.getHandlers();
1347         for (Handler h : targets) {
1348             logger.removeHandler(h);
1349             try {
1350                 h.close();
1351             } catch (Exception ex) {
1352                 // Problems closing a handler?  Keep going...
1353             }
1354         }








1355         String name = logger.getName();
1356         if (name != null && name.equals("")) {
1357             // This is the root logger.
1358             logger.setLevel(defaultLevel);
1359         } else {
1360             logger.setLevel(null);
1361         }
1362     }
1363 
1364     // get a list of whitespace separated classnames from a property.
1365     private String[] parseClassNames(String propertyName) {
1366         String hands = getProperty(propertyName);
1367         if (hands == null) {
1368             return new String[0];
1369         }
1370         hands = hands.trim();
1371         int ix = 0;
1372         final List<String> result = new ArrayList<>();
1373         while (ix < hands.length()) {
1374             int end = ix;


1391         }
1392         return result.toArray(new String[result.size()]);
1393     }
1394 
1395     /**
1396      * Reinitialize the logging properties and reread the logging configuration
1397      * from the given stream, which should be in java.util.Properties format.
1398      * Any {@linkplain #addConfigurationListener registered configuration
1399      * listener} will be invoked after the properties are read.
1400      * <p>
1401      * Any log level definitions in the new configuration file will be
1402      * applied using Logger.setLevel(), if the target Logger exists.
1403      *
1404      * @param ins       stream to read properties from
1405      * @exception  SecurityException  if a security manager exists and if
1406      *             the caller does not have LoggingPermission("control").
1407      * @exception  IOException if there are problems reading from the stream.
1408      */
1409     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1410         checkPermission();


















1411         reset();
1412 
1413         // Load the properties
1414         try {

1415             props.load(ins);
1416         } catch (IllegalArgumentException x) {
1417             // props.load may throw an IllegalArgumentException if the stream
1418             // contains malformed Unicode escape sequences.
1419             // We wrap that in an IOException as readConfiguration is
1420             // specified to throw IOException if there are problems reading
1421             // from the stream.
1422             // Note: new IOException(x.getMessage(), x) allow us to get a more
1423             // concise error message than new IOException(x);
1424             throw new IOException(x.getMessage(), x);
1425         }
1426 
1427         // Instantiate new configuration objects.
1428         String names[] = parseClassNames("config");
1429 
1430         for (String word : names) {
1431             try {
1432                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1433                 clz.newInstance();
1434             } catch (Exception ex) {
1435                 System.err.println("Can't load config class \"" + word + "\"");
1436                 System.err.println("" + ex);
1437                 // ex.printStackTrace();
1438             }
1439         }
1440 
1441         // Set levels on any pre-existing loggers, based on the new properties.
1442         setLevelsOnExistingLoggers();
1443 
1444         try {
1445             invokeConfigurationListeners();
1446         } finally {
1447             // Note that we need to reinitialize global handles when
1448             // they are first referenced.
1449             synchronized (this) {
1450                 initializedGlobalHandlers = false;








1451             }



1452         }




1453     }
1454 
1455     /**
1456      * Get the value of a logging property.
1457      * The method returns null if the property is not found.
1458      * @param name      property name
1459      * @return          property value
1460      */
1461     public String getProperty(String name) {
1462         return props.getProperty(name);
1463     }
1464 
1465     // Package private method to get a String property.
1466     // If the property is not defined we return the given
1467     // default value.
1468     String getStringProperty(String name, String defaultValue) {
1469         String val = getProperty(name);
1470         if (val == null) {
1471             return defaultValue;
1472         }


1559     // we return the defaultValue.
1560     Formatter getFormatterProperty(String name, Formatter defaultValue) {
1561         String val = getProperty(name);
1562         try {
1563             if (val != null) {
1564                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1565                 return (Formatter) clz.newInstance();
1566             }
1567         } catch (Exception ex) {
1568             // We got one of a variety of exceptions in creating the
1569             // class or creating an instance.
1570             // Drop through.
1571         }
1572         // We got an exception.  Return the defaultValue.
1573         return defaultValue;
1574     }
1575 
1576     // Private method to load the global handlers.
1577     // We do the real work lazily, when the global handlers
1578     // are first used.
1579     private synchronized void initializeGlobalHandlers() {
1580         if (initializedGlobalHandlers) {


1581             return;
1582         }
1583 
1584         initializedGlobalHandlers = true;
1585 
1586         if (deathImminent) {
1587             // Aaargh...
1588             // The VM is shutting down and our exit hook has been called.
1589             // Avoid allocating global handlers.
1590             return;




1591         }





1592         loadLoggerHandlers(rootLogger, null, "handlers");






1593     }
1594 
1595     static final Permission controlPermission = new LoggingPermission("control", null);
1596 
1597     void checkPermission() {
1598         SecurityManager sm = System.getSecurityManager();
1599         if (sm != null)
1600             sm.checkPermission(controlPermission);
1601     }
1602 
1603     /**
1604      * Check that the current context is trusted to modify the logging
1605      * configuration.  This requires LoggingPermission("control").
1606      * <p>
1607      * If the check fails we throw a SecurityException, otherwise
1608      * we return normally.
1609      *
1610      * @exception  SecurityException  if a security manager exists and if
1611      *             the caller does not have LoggingPermission("control").
1612      */


1667             initializeGlobalHandlers();
1668             super.addHandler(h);
1669         }
1670 
1671         @Override
1672         public void removeHandler(Handler h) {
1673             initializeGlobalHandlers();
1674             super.removeHandler(h);
1675         }
1676 
1677         @Override
1678         Handler[] accessCheckedHandlers() {
1679             initializeGlobalHandlers();
1680             return super.accessCheckedHandlers();
1681         }
1682     }
1683 
1684 
1685     // Private method to be called when the configuration has
1686     // changed to apply any level settings to any pre-existing loggers.
1687     synchronized private void setLevelsOnExistingLoggers() {
1688         Enumeration<?> enum_ = props.propertyNames();
1689         while (enum_.hasMoreElements()) {
1690             String key = (String)enum_.nextElement();
1691             if (!key.endsWith(".level")) {
1692                 // Not a level definition.
1693                 continue;
1694             }
1695             int ix = key.length() - 6;
1696             String name = key.substring(0, ix);
1697             Level level = getLevelProperty(key, null);
1698             if (level == null) {
1699                 System.err.println("Bad level value for property: " + key);
1700                 continue;
1701             }
1702             for (LoggerContext cx : contexts()) {
1703                 Logger l = cx.findLogger(name);
1704                 if (l == null) {
1705                     continue;
1706                 }
1707                 l.setLevel(level);




  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.util.concurrent.ConcurrentHashMap;
  35 import java.util.concurrent.CopyOnWriteArrayList;
  36 import java.util.concurrent.locks.ReentrantLock;
  37 import sun.misc.JavaAWTAccess;

  38 import sun.misc.SharedSecrets;
  39 
  40 /**
  41  * There is a single global LogManager object that is used to
  42  * maintain a set of shared state about Loggers and log services.
  43  * <p>
  44  * This LogManager object:
  45  * <ul>
  46  * <li> Manages a hierarchical namespace of Logger objects.  All
  47  *      named Loggers are stored in this namespace.
  48  * <li> Manages a set of logging control properties.  These are
  49  *      simple key-value pairs that can be used by Handlers and
  50  *      other logging objects to configure themselves.
  51  * </ul>
  52  * <p>
  53  * The global LogManager object can be retrieved using LogManager.getLogManager().
  54  * The LogManager object is created during class initialization and
  55  * cannot subsequently be changed.
  56  * <p>
  57  * At startup the LogManager class is located using the


 163     // be able to see a partially constructed 'props' object.
 164     // (seeing a partially constructed 'props' object can result in
 165     // NPE being thrown in Hashtable.get(), because it leaves the door
 166     // open for props.getProperties() to be called before the construcor
 167     // of Hashtable is actually completed).
 168     private volatile Properties props = new Properties();
 169     private final static Level defaultLevel = Level.INFO;
 170 
 171     // LoggerContext for system loggers and user loggers
 172     private final LoggerContext systemContext = new SystemLoggerContext();
 173     private final LoggerContext userContext = new LoggerContext();
 174     // non final field - make it volatile to make sure that other threads
 175     // will see the new value once ensureLogManagerInitialized() has finished
 176     // executing.
 177     private volatile Logger rootLogger;
 178     // Have we done the primordial reading of the configuration file?
 179     // (Must be done after a suitable amount of java.lang.System
 180     // initialization has been done)
 181     private volatile boolean readPrimordialConfiguration;
 182     // Have we initialized global (root) handlers yet?
 183     // This gets set to STATE_UNINITIALIZED in readConfiguration
 184     private static final int
 185             STATE_INITIALIZED = 0, // initial state
 186             STATE_INITIALIZING = 1,
 187             STATE_UNINITIALIZED = 2,
 188             STATE_SHUTDOWN = 3;    // terminal state
 189     private volatile int globalHandlersState; // = STATE_INITIALIZED;
 190     // A concurrency lock for reset(), readConfiguration() and Cleaner.
 191     private final ReentrantLock configurationLock = new ReentrantLock();
 192 
 193     // This list contains the loggers for which some handlers have been
 194     // explicitly configured in the configuration file.
 195     // It prevents these loggers from being arbitrarily garbage collected.
 196     private static final class CloseOnReset {
 197         private final Logger logger;
 198         private CloseOnReset(Logger ref) {
 199             this.logger = Objects.requireNonNull(ref);
 200         }
 201         @Override
 202         public boolean equals(Object other) {
 203             return (other instanceof CloseOnReset) && ((CloseOnReset)other).logger == logger;
 204         }
 205         @Override
 206         public int hashCode() {
 207             return System.identityHashCode(logger);
 208         }
 209         public Logger get() {
 210             return logger;
 211         }


 237                             Class<?> clz = Thread.currentThread()
 238                                     .getContextClassLoader().loadClass(cname);
 239                             mgr = (LogManager) clz.newInstance();
 240                         }
 241                     }
 242                 } catch (Exception ex) {
 243                     System.err.println("Could not load Logmanager \"" + cname + "\"");
 244                     ex.printStackTrace();
 245                 }
 246                 if (mgr == null) {
 247                     mgr = new LogManager();
 248                 }
 249                 return mgr;
 250 
 251             }
 252         });
 253     }
 254 
 255     // This private class is used as a shutdown hook.
 256     // It does a "reset" to close all open handlers.
 257     private class Cleaner extends Thread {
 258 
 259         private Cleaner() {
 260             /* Set context class loader to null in order to avoid
 261              * keeping a strong reference to an application classloader.
 262              */
 263             this.setContextClassLoader(null);
 264         }
 265 
 266         @Override
 267         public void run() {
 268             // This is to ensure the LogManager.<clinit> is completed
 269             // before synchronized block. Otherwise deadlocks are possible.
 270             LogManager mgr = manager;
 271 
 272             configurationLock.lock();
 273             // temporarily block any ongoing logging requests until reset finishes
 274             // by setting globalHandlersState to STATE_INITIALIZING
 275             globalHandlersState = STATE_INITIALIZING;
 276             try {
 277                 // Do a reset to close all active handlers which leaves state at
 278                 // STATE_INITIALIZING...


 279                 reset();
 280             } finally {
 281                 // set globalHandlersState to a final STATE_SHUTDOWN so
 282                 // that no attempts will be made to initialize them again.
 283                 globalHandlersState = STATE_SHUTDOWN;
 284                 configurationLock.unlock();
 285             }
 286         }
 287     }
 288 
 289 
 290     /**
 291      * Protected constructor.  This is protected so that container applications
 292      * (such as J2EE containers) can subclass the object.  It is non-public as
 293      * it is intended that there only be one LogManager object, whose value is
 294      * retrieved by calling LogManager.getLogManager.
 295      */
 296     protected LogManager() {
 297         this(checkSubclassPermissions());
 298     }
 299 
 300     private LogManager(Void checked) {
 301 
 302         // Add a shutdown hook to close the global handlers.
 303         try {
 304             Runtime.getRuntime().addShutdownHook(new Cleaner());
 305         } catch (IllegalStateException e) {


1306         }
1307         try (final InputStream in = new FileInputStream(fname)) {
1308             final BufferedInputStream bin = new BufferedInputStream(in);
1309             readConfiguration(bin);
1310         }
1311     }
1312 
1313     /**
1314      * Reset the logging configuration.
1315      * <p>
1316      * For all named loggers, the reset operation removes and closes
1317      * all Handlers and (except for the root logger) sets the level
1318      * to null.  The root logger's level is set to Level.INFO.
1319      *
1320      * @exception  SecurityException  if a security manager exists and if
1321      *             the caller does not have LoggingPermission("control").
1322      */
1323 
1324     public void reset() throws SecurityException {
1325         checkPermission();
1326 
1327         List<CloseOnReset> persistent;
1328 
1329         // We don't want reset() and readConfiguration()
1330         // to run in parallel
1331         configurationLock.lock();
1332         try {
1333             if (globalHandlersState == STATE_SHUTDOWN) {
1334                 // already in terminal state
1335                 return;
1336             }
1337             // install new empty properties
1338             props = new Properties();
1339             // make sure we keep the loggers persistent until reset is done.
1340             // Those are the loggers for which we previously created a
1341             // handler from the configuration, and we need to prevent them
1342             // from being gc'ed until those handlers are closed.
1343             persistent = new ArrayList<>(closeOnResetLoggers);
1344             closeOnResetLoggers.clear();
1345 
1346             // Since we are doing a reset we no longer want to initialize
1347             // the global handlers, if they haven't been initialized yet.
1348             // When globalHandlersState == STATE_INITIALIZING it means
1349             // we have been called from readConfiguration that is going to set
1350             // final state itself. Otherwise we set is to STATE_INITIALIZED.
1351             if (globalHandlersState != STATE_INITIALIZING) {
1352                 globalHandlersState = STATE_INITIALIZED;
1353             }
1354 
1355             for (LoggerContext cx : contexts()) {
1356                 resetLoggerContext(cx);
1357             }
1358 
1359             persistent.clear();
1360         } finally {
1361             configurationLock.unlock();
1362         }
1363     }
1364 
1365     private void resetLoggerContext(LoggerContext cx) {
1366         Enumeration<String> enum_ = cx.getLoggerNames();
1367         while (enum_.hasMoreElements()) {
1368             String name = enum_.nextElement();
1369             Logger logger = cx.findLogger(name);
1370             if (logger != null) {
1371                 resetLogger(logger);
1372             }
1373         }
1374     }


1375 
1376     private void closeHandlers(Logger logger) {


1377         Handler[] targets = logger.getHandlers();
1378         for (Handler h : targets) {
1379             logger.removeHandler(h);
1380             try {
1381                 h.close();
1382             } catch (Exception ex) {
1383                 // Problems closing a handler?  Keep going...
1384             }
1385         }
1386     }
1387 
1388     // Private method to reset an individual target logger.
1389     private void resetLogger(Logger logger) {
1390         // Close all the Logger handlers.
1391         closeHandlers(logger);
1392 
1393         // Reset Logger level
1394         String name = logger.getName();
1395         if (name != null && name.equals("")) {
1396             // This is the root logger.
1397             logger.setLevel(defaultLevel);
1398         } else {
1399             logger.setLevel(null);
1400         }
1401     }
1402 
1403     // get a list of whitespace separated classnames from a property.
1404     private String[] parseClassNames(String propertyName) {
1405         String hands = getProperty(propertyName);
1406         if (hands == null) {
1407             return new String[0];
1408         }
1409         hands = hands.trim();
1410         int ix = 0;
1411         final List<String> result = new ArrayList<>();
1412         while (ix < hands.length()) {
1413             int end = ix;


1430         }
1431         return result.toArray(new String[result.size()]);
1432     }
1433 
1434     /**
1435      * Reinitialize the logging properties and reread the logging configuration
1436      * from the given stream, which should be in java.util.Properties format.
1437      * Any {@linkplain #addConfigurationListener registered configuration
1438      * listener} will be invoked after the properties are read.
1439      * <p>
1440      * Any log level definitions in the new configuration file will be
1441      * applied using Logger.setLevel(), if the target Logger exists.
1442      *
1443      * @param ins       stream to read properties from
1444      * @exception  SecurityException  if a security manager exists and if
1445      *             the caller does not have LoggingPermission("control").
1446      * @exception  IOException if there are problems reading from the stream.
1447      */
1448     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1449         checkPermission();
1450 
1451         // We don't want reset() and readConfiguration() to run
1452         // in parallel.
1453         configurationLock.lock();
1454         try {
1455             if (globalHandlersState == STATE_SHUTDOWN) {
1456                 // already in terminal state: don't even bother to read the
1457                 // configuration
1458                 return;
1459             }
1460 
1461             // change state to STATE_INITIALIZING so that reset() doesn't change it to
1462             // STATE_INITIALIZED just yet...
1463             globalHandlersState = STATE_INITIALIZING;
1464             try {
1465                 // reset configuration which leaves globalHandlersState at STATE_INITIALIZING
1466                 // so that while reading configuration, any ongoing logging requests block and
1467                 // wait for the outcome (see the end of this try statement)
1468                 reset();
1469 

1470                 try {
1471                     // Load the properties
1472                     props.load(ins);
1473                 } catch (IllegalArgumentException x) {
1474                     // props.load may throw an IllegalArgumentException if the stream
1475                     // contains malformed Unicode escape sequences.
1476                     // We wrap that in an IOException as readConfiguration is
1477                     // specified to throw IOException if there are problems reading
1478                     // from the stream.
1479                     // Note: new IOException(x.getMessage(), x) allow us to get a more
1480                     // concise error message than new IOException(x);
1481                     throw new IOException(x.getMessage(), x);
1482                 }
1483 
1484                 // Instantiate new configuration objects.
1485                 String names[] = parseClassNames("config");
1486 
1487                 for (String word : names) {
1488                     try {
1489                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1490                         clz.newInstance();
1491                     } catch (Exception ex) {
1492                         System.err.println("Can't load config class \"" + word + "\"");
1493                         System.err.println("" + ex);
1494                         // ex.printStackTrace();
1495                     }
1496                 }
1497 
1498                 // Set levels on any pre-existing loggers, based on the new properties.
1499                 setLevelsOnExistingLoggers();
1500 



1501                 // Note that we need to reinitialize global handles when
1502                 // they are first referenced.
1503                 // Note: Marking global handlers as not initialized must be done
1504                 // before unlocking.
1505                 globalHandlersState = STATE_UNINITIALIZED;
1506             } catch (Throwable t) {
1507                 // If there were any trouble, then set state to STATE_INITIALIZED
1508                 // so that no global handlers reinitialization is performed on not fully
1509                 // initialized configuration.
1510                 globalHandlersState = STATE_INITIALIZED;
1511                 // re-throw
1512                 throw t;
1513             }
1514 
1515         } finally {
1516             configurationLock.unlock();
1517         }
1518 
1519         // should be called out of lock to avoid dead-lock situations
1520         // when user code is involved
1521         invokeConfigurationListeners();
1522     }
1523 
1524     /**
1525      * Get the value of a logging property.
1526      * The method returns null if the property is not found.
1527      * @param name      property name
1528      * @return          property value
1529      */
1530     public String getProperty(String name) {
1531         return props.getProperty(name);
1532     }
1533 
1534     // Package private method to get a String property.
1535     // If the property is not defined we return the given
1536     // default value.
1537     String getStringProperty(String name, String defaultValue) {
1538         String val = getProperty(name);
1539         if (val == null) {
1540             return defaultValue;
1541         }


1628     // we return the defaultValue.
1629     Formatter getFormatterProperty(String name, Formatter defaultValue) {
1630         String val = getProperty(name);
1631         try {
1632             if (val != null) {
1633                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1634                 return (Formatter) clz.newInstance();
1635             }
1636         } catch (Exception ex) {
1637             // We got one of a variety of exceptions in creating the
1638             // class or creating an instance.
1639             // Drop through.
1640         }
1641         // We got an exception.  Return the defaultValue.
1642         return defaultValue;
1643     }
1644 
1645     // Private method to load the global handlers.
1646     // We do the real work lazily, when the global handlers
1647     // are first used.
1648     private void initializeGlobalHandlers() {
1649         int state = globalHandlersState;
1650         if (state == STATE_INITIALIZED || state == STATE_SHUTDOWN) {
1651             // Nothing to do: return.
1652             return;
1653         }
1654 
1655         // If we have not initialized global handlers yet (or need to
1656         // reinitialize them), lets do it now (this case is indicated by
1657         // globalHandlersState == STATE_UNINITIALIZED).
1658         // If we are in the process of initializing global handlers we
1659         // also need to lock & wait (this case is indicated by
1660         // globalHandlersState == STATE_INITIALIZING).
1661         // So in either case we need to acquire the lock.
1662         configurationLock.lock();
1663         try {
1664             if (globalHandlersState != STATE_UNINITIALIZED) {
1665                 return; // recursive call or nothing to do
1666             }
1667             // set globalHandlersState to STATE_INITIALIZING first to avoid
1668             // getting an infinite recursion when loadLoggerHandlers(...)
1669             // is going to call addHandler(...)
1670             globalHandlersState = STATE_INITIALIZING;
1671             try {
1672                 loadLoggerHandlers(rootLogger, null, "handlers");
1673             } finally {
1674                 globalHandlersState = STATE_INITIALIZED;
1675             }
1676         } finally {
1677             configurationLock.unlock();
1678         }
1679     }
1680 
1681     static final Permission controlPermission = new LoggingPermission("control", null);
1682 
1683     void checkPermission() {
1684         SecurityManager sm = System.getSecurityManager();
1685         if (sm != null)
1686             sm.checkPermission(controlPermission);
1687     }
1688 
1689     /**
1690      * Check that the current context is trusted to modify the logging
1691      * configuration.  This requires LoggingPermission("control").
1692      * <p>
1693      * If the check fails we throw a SecurityException, otherwise
1694      * we return normally.
1695      *
1696      * @exception  SecurityException  if a security manager exists and if
1697      *             the caller does not have LoggingPermission("control").
1698      */


1753             initializeGlobalHandlers();
1754             super.addHandler(h);
1755         }
1756 
1757         @Override
1758         public void removeHandler(Handler h) {
1759             initializeGlobalHandlers();
1760             super.removeHandler(h);
1761         }
1762 
1763         @Override
1764         Handler[] accessCheckedHandlers() {
1765             initializeGlobalHandlers();
1766             return super.accessCheckedHandlers();
1767         }
1768     }
1769 
1770 
1771     // Private method to be called when the configuration has
1772     // changed to apply any level settings to any pre-existing loggers.
1773     private void setLevelsOnExistingLoggers() {
1774         Enumeration<?> enum_ = props.propertyNames();
1775         while (enum_.hasMoreElements()) {
1776             String key = (String)enum_.nextElement();
1777             if (!key.endsWith(".level")) {
1778                 // Not a level definition.
1779                 continue;
1780             }
1781             int ix = key.length() - 6;
1782             String name = key.substring(0, ix);
1783             Level level = getLevelProperty(key, null);
1784             if (level == null) {
1785                 System.err.println("Bad level value for property: " + key);
1786                 continue;
1787             }
1788             for (LoggerContext cx : contexts()) {
1789                 Logger l = cx.findLogger(name);
1790                 if (l == null) {
1791                     continue;
1792                 }
1793                 l.setLevel(level);


< prev index next >