< 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.


 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         }


 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());


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


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


 255         });
 256     }
 257 
 258     // This private class is used as a shutdown hook.
 259     // It does a "reset" to close all open handlers.
 260     private class Cleaner extends ManagedLocalsThread {
 261 
 262         private Cleaner() {
 263             /* Set context class loader to null in order to avoid
 264              * keeping a strong reference to an application classloader.
 265              */
 266             this.setContextClassLoader(null);
 267         }
 268 
 269         @Override
 270         public void run() {
 271             // This is to ensure the LogManager.<clinit> is completed
 272             // before synchronized block. Otherwise deadlocks are possible.
 273             LogManager mgr = manager;
 274 
 275             // set globalHandlersState to STATE_SHUTTING_DOWN atomically so that
 276             // no attempts are made to (re)initialize the handlers or (re)read
 277             // the configuration again. This is also a signal for reset() to
 278             // change the state to terminal STATE_SHUTDOWN.
 279             configurationLock.lock();
 280             globalHandlersState = STATE_SHUTTING_DOWN;
 281             configurationLock.unlock();
 282 
 283             // Do a reset to close all active handlers which transitions state
 284             // to STATE_SHUTDOWN.
 285             reset();
 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());


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             if (globalHandlersState == STATE_SHUTTING_DOWN) {
1347                 // if reset has been called from shutdown-hook (Cleaner),
1348                 // then transition state to terminal STATE_SHUTDOWN.
1349                 globalHandlersState = STATE_SHUTDOWN;
1350             } else if (globalHandlersState == STATE_READING_CONFIG) {
1351                 // if reset has been called from readConfiguration() which
1352                 // already holds the lock then the state will be changed by
1353                 // readConfiguration() depending on the outcome.
1354             } else {
1355                 // ...user calling reset()...
1356                 // Since we are doing a reset we no longer want to initialize
1357                 // the global handlers, if they haven't been initialized yet.
1358                 globalHandlersState = STATE_INITIALIZED;
1359             }
1360 
1361             for (LoggerContext cx : contexts()) {
1362                 resetLoggerContext(cx);
1363             }
1364 
1365             persistent.clear();
1366         } finally {
1367             configurationLock.unlock();
1368         }
1369     }
1370 
1371     private void resetLoggerContext(LoggerContext cx) {
1372         Enumeration<String> enum_ = cx.getLoggerNames();
1373         while (enum_.hasMoreElements()) {
1374             String name = enum_.nextElement();
1375             Logger logger = cx.findLogger(name);
1376             if (logger != null) {
1377                 resetLogger(logger);
1378             }
1379         }
1380     }


1381 
1382     private void closeHandlers(Logger logger) {


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


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

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



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


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


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


< prev index next >