jdk/src/java.logging/share/classes/java/util/logging/LogManager.java
changeset 30643 1fcf87dbdc3c
parent 29919 be906afc335b
child 31150 2aa1d300cd75
equal deleted inserted replaced
30642:d9891f85d583 30643:1fcf87dbdc3c
    31 import java.security.*;
    31 import java.security.*;
    32 import java.lang.ref.ReferenceQueue;
    32 import java.lang.ref.ReferenceQueue;
    33 import java.lang.ref.WeakReference;
    33 import java.lang.ref.WeakReference;
    34 import java.util.concurrent.ConcurrentHashMap;
    34 import java.util.concurrent.ConcurrentHashMap;
    35 import java.util.concurrent.CopyOnWriteArrayList;
    35 import java.util.concurrent.CopyOnWriteArrayList;
       
    36 import java.util.concurrent.locks.ReentrantLock;
    36 import sun.misc.JavaAWTAccess;
    37 import sun.misc.JavaAWTAccess;
    37 import sun.misc.ManagedLocalsThread;
    38 import sun.misc.ManagedLocalsThread;
    38 import sun.misc.SharedSecrets;
    39 import sun.misc.SharedSecrets;
    39 
    40 
    40 /**
    41 /**
   178     // Have we done the primordial reading of the configuration file?
   179     // Have we done the primordial reading of the configuration file?
   179     // (Must be done after a suitable amount of java.lang.System
   180     // (Must be done after a suitable amount of java.lang.System
   180     // initialization has been done)
   181     // initialization has been done)
   181     private volatile boolean readPrimordialConfiguration;
   182     private volatile boolean readPrimordialConfiguration;
   182     // Have we initialized global (root) handlers yet?
   183     // Have we initialized global (root) handlers yet?
   183     // This gets set to false in readConfiguration
   184     // This gets set to STATE_UNINITIALIZED in readConfiguration
   184     private boolean initializedGlobalHandlers = true;
   185     private static final int
   185     // True if JVM death is imminent and the exit hook has been called.
   186             STATE_INITIALIZED = 0, // initial state
   186     private boolean deathImminent;
   187             STATE_INITIALIZING = 1,
       
   188             STATE_READING_CONFIG = 2,
       
   189             STATE_UNINITIALIZED = 3,
       
   190             STATE_SHUTDOWN = 4;    // terminal state
       
   191     private volatile int globalHandlersState; // = STATE_INITIALIZED;
       
   192     // A concurrency lock for reset(), readConfiguration() and Cleaner.
       
   193     private final ReentrantLock configurationLock = new ReentrantLock();
   187 
   194 
   188     // This list contains the loggers for which some handlers have been
   195     // This list contains the loggers for which some handlers have been
   189     // explicitly configured in the configuration file.
   196     // explicitly configured in the configuration file.
   190     // It prevents these loggers from being arbitrarily garbage collected.
   197     // It prevents these loggers from being arbitrarily garbage collected.
   191     private static final class CloseOnReset {
   198     private static final class CloseOnReset {
   262         public void run() {
   269         public void run() {
   263             // This is to ensure the LogManager.<clinit> is completed
   270             // This is to ensure the LogManager.<clinit> is completed
   264             // before synchronized block. Otherwise deadlocks are possible.
   271             // before synchronized block. Otherwise deadlocks are possible.
   265             LogManager mgr = manager;
   272             LogManager mgr = manager;
   266 
   273 
   267             // If the global handlers haven't been initialized yet, we
   274             // set globalHandlersState to STATE_SHUTDOWN atomically so that
   268             // don't want to initialize them just so we can close them!
   275             // no attempts are made to (re)initialize the handlers or (re)read
   269             synchronized (LogManager.this) {
   276             // the configuration again. This is terminal state.
   270                 // Note that death is imminent.
   277             configurationLock.lock();
   271                 deathImminent = true;
   278             globalHandlersState = STATE_SHUTDOWN;
   272                 initializedGlobalHandlers = true;
   279             configurationLock.unlock();
   273             }
       
   274 
   280 
   275             // Do a reset to close all active handlers.
   281             // Do a reset to close all active handlers.
   276             reset();
   282             reset();
   277         }
   283         }
   278     }
   284     }
  1312      *             the caller does not have LoggingPermission("control").
  1318      *             the caller does not have LoggingPermission("control").
  1313      */
  1319      */
  1314 
  1320 
  1315     public void reset() throws SecurityException {
  1321     public void reset() throws SecurityException {
  1316         checkPermission();
  1322         checkPermission();
       
  1323 
  1317         List<CloseOnReset> persistent;
  1324         List<CloseOnReset> persistent;
  1318         synchronized (this) {
  1325 
       
  1326         // We don't want reset() and readConfiguration()
       
  1327         // to run in parallel
       
  1328         configurationLock.lock();
       
  1329         try {
       
  1330             // install new empty properties
  1319             props = new Properties();
  1331             props = new Properties();
  1320             // make sure we keep the loggers persistent until reset is done.
  1332             // make sure we keep the loggers persistent until reset is done.
  1321             // Those are the loggers for which we previously created a
  1333             // Those are the loggers for which we previously created a
  1322             // handler from the configuration, and we need to prevent them
  1334             // handler from the configuration, and we need to prevent them
  1323             // from being gc'ed until those handlers are closed.
  1335             // from being gc'ed until those handlers are closed.
  1324             persistent = new ArrayList<>(closeOnResetLoggers);
  1336             persistent = new ArrayList<>(closeOnResetLoggers);
  1325             closeOnResetLoggers.clear();
  1337             closeOnResetLoggers.clear();
  1326             // Since we are doing a reset we no longer want to initialize
  1338 
  1327             // the global handlers, if they haven't been initialized yet.
  1339             // if reset has been called from shutdown-hook (Cleaner),
  1328             initializedGlobalHandlers = true;
  1340             // or if reset has been called from readConfiguration() which
  1329         }
  1341             // already holds the lock and will change the state itself,
  1330         for (LoggerContext cx : contexts()) {
  1342             // then do not change state here...
  1331             Enumeration<String> enum_ = cx.getLoggerNames();
  1343             if (globalHandlersState != STATE_SHUTDOWN &&
  1332             while (enum_.hasMoreElements()) {
  1344                 globalHandlersState != STATE_READING_CONFIG) {
  1333                 String name = enum_.nextElement();
  1345                 // ...else user called reset()...
  1334                 Logger logger = cx.findLogger(name);
  1346                 // Since we are doing a reset we no longer want to initialize
  1335                 if (logger != null) {
  1347                 // the global handlers, if they haven't been initialized yet.
  1336                     resetLogger(logger);
  1348                 globalHandlersState = STATE_INITIALIZED;
  1337                 }
  1349             }
  1338             }
  1350 
  1339         }
  1351             for (LoggerContext cx : contexts()) {
  1340         persistent.clear();
  1352                 resetLoggerContext(cx);
  1341     }
  1353             }
  1342 
  1354 
  1343     // Private method to reset an individual target logger.
  1355             persistent.clear();
  1344     private void resetLogger(Logger logger) {
  1356         } finally {
  1345         // Close all the Logger's handlers.
  1357             configurationLock.unlock();
       
  1358         }
       
  1359     }
       
  1360 
       
  1361     private void resetLoggerContext(LoggerContext cx) {
       
  1362         Enumeration<String> enum_ = cx.getLoggerNames();
       
  1363         while (enum_.hasMoreElements()) {
       
  1364             String name = enum_.nextElement();
       
  1365             Logger logger = cx.findLogger(name);
       
  1366             if (logger != null) {
       
  1367                 resetLogger(logger);
       
  1368             }
       
  1369         }
       
  1370     }
       
  1371 
       
  1372     private void closeHandlers(Logger logger) {
  1346         Handler[] targets = logger.getHandlers();
  1373         Handler[] targets = logger.getHandlers();
  1347         for (Handler h : targets) {
  1374         for (Handler h : targets) {
  1348             logger.removeHandler(h);
  1375             logger.removeHandler(h);
  1349             try {
  1376             try {
  1350                 h.close();
  1377                 h.close();
  1351             } catch (Exception ex) {
  1378             } catch (Exception ex) {
  1352                 // Problems closing a handler?  Keep going...
  1379                 // Problems closing a handler?  Keep going...
  1353             }
  1380             }
  1354         }
  1381         }
       
  1382     }
       
  1383 
       
  1384     // Private method to reset an individual target logger.
       
  1385     private void resetLogger(Logger logger) {
       
  1386         // Close all the Logger handlers.
       
  1387         closeHandlers(logger);
       
  1388 
       
  1389         // Reset Logger level
  1355         String name = logger.getName();
  1390         String name = logger.getName();
  1356         if (name != null && name.equals("")) {
  1391         if (name != null && name.equals("")) {
  1357             // This is the root logger.
  1392             // This is the root logger.
  1358             logger.setLevel(defaultLevel);
  1393             logger.setLevel(defaultLevel);
  1359         } else {
  1394         } else {
  1406      *             the caller does not have LoggingPermission("control").
  1441      *             the caller does not have LoggingPermission("control").
  1407      * @exception  IOException if there are problems reading from the stream.
  1442      * @exception  IOException if there are problems reading from the stream.
  1408      */
  1443      */
  1409     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
  1444     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
  1410         checkPermission();
  1445         checkPermission();
  1411         reset();
  1446 
  1412 
  1447         // We don't want reset() and readConfiguration() to run
  1413         // Load the properties
  1448         // in parallel.
       
  1449         configurationLock.lock();
  1414         try {
  1450         try {
  1415             props.load(ins);
  1451             if (globalHandlersState == STATE_SHUTDOWN) {
  1416         } catch (IllegalArgumentException x) {
  1452                 // already in terminal state: don't even bother
  1417             // props.load may throw an IllegalArgumentException if the stream
  1453                 // to read the configuration
  1418             // contains malformed Unicode escape sequences.
  1454                 return;
  1419             // We wrap that in an IOException as readConfiguration is
  1455             }
  1420             // specified to throw IOException if there are problems reading
  1456 
  1421             // from the stream.
  1457             // change state to STATE_READING_CONFIG to signal reset() to not change it
  1422             // Note: new IOException(x.getMessage(), x) allow us to get a more
  1458             globalHandlersState = STATE_READING_CONFIG;
  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 {
  1459             try {
  1432                 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
  1460                 // reset configuration which leaves globalHandlersState at STATE_READING_CONFIG
  1433                 clz.newInstance();
  1461                 // so that while reading configuration, any ongoing logging requests block and
  1434             } catch (Exception ex) {
  1462                 // wait for the outcome (see the end of this try statement)
  1435                 System.err.println("Can't load config class \"" + word + "\"");
  1463                 reset();
  1436                 System.err.println("" + ex);
  1464 
  1437                 // ex.printStackTrace();
  1465                 try {
  1438             }
  1466                     // Load the properties
  1439         }
  1467                     props.load(ins);
  1440 
  1468                 } catch (IllegalArgumentException x) {
  1441         // Set levels on any pre-existing loggers, based on the new properties.
  1469                     // props.load may throw an IllegalArgumentException if the stream
  1442         setLevelsOnExistingLoggers();
  1470                     // contains malformed Unicode escape sequences.
  1443 
  1471                     // We wrap that in an IOException as readConfiguration is
  1444         try {
  1472                     // specified to throw IOException if there are problems reading
  1445             invokeConfigurationListeners();
  1473                     // from the stream.
       
  1474                     // Note: new IOException(x.getMessage(), x) allow us to get a more
       
  1475                     // concise error message than new IOException(x);
       
  1476                     throw new IOException(x.getMessage(), x);
       
  1477                 }
       
  1478 
       
  1479                 // Instantiate new configuration objects.
       
  1480                 String names[] = parseClassNames("config");
       
  1481 
       
  1482                 for (String word : names) {
       
  1483                     try {
       
  1484                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
       
  1485                         clz.newInstance();
       
  1486                     } catch (Exception ex) {
       
  1487                         System.err.println("Can't load config class \"" + word + "\"");
       
  1488                         System.err.println("" + ex);
       
  1489                         // ex.printStackTrace();
       
  1490                     }
       
  1491                 }
       
  1492 
       
  1493                 // Set levels on any pre-existing loggers, based on the new properties.
       
  1494                 setLevelsOnExistingLoggers();
       
  1495 
       
  1496                 // Note that we need to reinitialize global handles when
       
  1497                 // they are first referenced.
       
  1498                 globalHandlersState = STATE_UNINITIALIZED;
       
  1499             } catch (Throwable t) {
       
  1500                 // If there were any trouble, then set state to STATE_INITIALIZED
       
  1501                 // so that no global handlers reinitialization is performed on not fully
       
  1502                 // initialized configuration.
       
  1503                 globalHandlersState = STATE_INITIALIZED;
       
  1504                 // re-throw
       
  1505                 throw t;
       
  1506             }
  1446         } finally {
  1507         } finally {
  1447             // Note that we need to reinitialize global handles when
  1508             configurationLock.unlock();
  1448             // they are first referenced.
  1509         }
  1449             synchronized (this) {
  1510 
  1450                 initializedGlobalHandlers = false;
  1511         // should be called out of lock to avoid dead-lock situations
  1451             }
  1512         // when user code is involved
  1452         }
  1513         invokeConfigurationListeners();
  1453     }
  1514     }
  1454 
  1515 
  1455     /**
  1516     /**
  1456      * Get the value of a logging property.
  1517      * Get the value of a logging property.
  1457      * The method returns null if the property is not found.
  1518      * The method returns null if the property is not found.
  1574     }
  1635     }
  1575 
  1636 
  1576     // Private method to load the global handlers.
  1637     // Private method to load the global handlers.
  1577     // We do the real work lazily, when the global handlers
  1638     // We do the real work lazily, when the global handlers
  1578     // are first used.
  1639     // are first used.
  1579     private synchronized void initializeGlobalHandlers() {
  1640     private void initializeGlobalHandlers() {
  1580         if (initializedGlobalHandlers) {
  1641         int state = globalHandlersState;
       
  1642         if (state == STATE_INITIALIZED ||
       
  1643             state == STATE_SHUTDOWN) {
       
  1644             // Nothing to do: return.
  1581             return;
  1645             return;
  1582         }
  1646         }
  1583 
  1647 
  1584         initializedGlobalHandlers = true;
  1648         // If we have not initialized global handlers yet (or need to
  1585 
  1649         // reinitialize them), lets do it now (this case is indicated by
  1586         if (deathImminent) {
  1650         // globalHandlersState == STATE_UNINITIALIZED).
  1587             // Aaargh...
  1651         // If we are in the process of initializing global handlers we
  1588             // The VM is shutting down and our exit hook has been called.
  1652         // also need to lock & wait (this case is indicated by
  1589             // Avoid allocating global handlers.
  1653         // globalHandlersState == STATE_INITIALIZING).
  1590             return;
  1654         // If we are in the process of reading configuration we also need to
  1591         }
  1655         // wait to see what the outcome will be (this case
  1592         loadLoggerHandlers(rootLogger, null, "handlers");
  1656         // is indicated by globalHandlersState == STATE_READING_CONFIG)
       
  1657         // So in either case we need to wait for the lock.
       
  1658         configurationLock.lock();
       
  1659         try {
       
  1660             if (globalHandlersState != STATE_UNINITIALIZED) {
       
  1661                 return; // recursive call or nothing to do
       
  1662             }
       
  1663             // set globalHandlersState to STATE_INITIALIZING first to avoid
       
  1664             // getting an infinite recursion when loadLoggerHandlers(...)
       
  1665             // is going to call addHandler(...)
       
  1666             globalHandlersState = STATE_INITIALIZING;
       
  1667             try {
       
  1668                 loadLoggerHandlers(rootLogger, null, "handlers");
       
  1669             } finally {
       
  1670                 globalHandlersState = STATE_INITIALIZED;
       
  1671             }
       
  1672         } finally {
       
  1673             configurationLock.unlock();
       
  1674         }
  1593     }
  1675     }
  1594 
  1676 
  1595     static final Permission controlPermission = new LoggingPermission("control", null);
  1677     static final Permission controlPermission = new LoggingPermission("control", null);
  1596 
  1678 
  1597     void checkPermission() {
  1679     void checkPermission() {
  1682     }
  1764     }
  1683 
  1765 
  1684 
  1766 
  1685     // Private method to be called when the configuration has
  1767     // Private method to be called when the configuration has
  1686     // changed to apply any level settings to any pre-existing loggers.
  1768     // changed to apply any level settings to any pre-existing loggers.
  1687     synchronized private void setLevelsOnExistingLoggers() {
  1769     private void setLevelsOnExistingLoggers() {
  1688         Enumeration<?> enum_ = props.propertyNames();
  1770         Enumeration<?> enum_ = props.propertyNames();
  1689         while (enum_.hasMoreElements()) {
  1771         while (enum_.hasMoreElements()) {
  1690             String key = (String)enum_.nextElement();
  1772             String key = (String)enum_.nextElement();
  1691             if (!key.endsWith(".level")) {
  1773             if (!key.endsWith(".level")) {
  1692                 // Not a level definition.
  1774                 // Not a level definition.