< 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             // Do a reset to close all active handlers and set
 273             // globalHandlersState to a final STATE_SHUTDOWN so
 274             // that no attempts will be made to initialize them again.
 275             reset(STATE_SHUTDOWN);






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


1296         }
1297         try (final InputStream in = new FileInputStream(fname)) {
1298             final BufferedInputStream bin = new BufferedInputStream(in);
1299             readConfiguration(bin);
1300         }
1301     }
1302 
1303     /**
1304      * Reset the logging configuration.
1305      * <p>
1306      * For all named loggers, the reset operation removes and closes
1307      * all Handlers and (except for the root logger) sets the level
1308      * to null.  The root logger's level is set to Level.INFO.
1309      *
1310      * @exception  SecurityException  if a security manager exists and if
1311      *             the caller does not have LoggingPermission("control").
1312      */
1313 
1314     public void reset() throws SecurityException {
1315         checkPermission();
1316         // Since we are doing a reset we no longer want to initialize
1317         // the global handlers, if they haven't been initialized yet.
1318         reset(STATE_INITIALIZED);
1319     }
1320 
1321     private void reset(int newGlobalHandlersState) {
1322         List<CloseOnReset> persistent;
1323 
1324         // We don't want reset() and readConfiguration()
1325         // to run in parallel
1326         configurationLock.lock();
1327         try {
1328             if (globalHandlersState == STATE_SHUTDOWN) {
1329                 // already in terminal state
1330                 return;
1331             }
1332             // install new empty properties
1333             props = new Properties();
1334             // make sure we keep the loggers persistent until reset is done.
1335             // Those are the loggers for which we previously created a
1336             // handler from the configuration, and we need to prevent them
1337             // from being gc'ed until those handlers are closed.
1338             persistent = new ArrayList<>(closeOnResetLoggers);
1339             closeOnResetLoggers.clear();
1340 
1341             globalHandlersState = newGlobalHandlersState;
1342 

1343             for (LoggerContext cx : contexts()) {
1344                 resetLoggerContext(cx);
1345             }
1346 
1347             persistent.clear();
1348         } finally {
1349             configurationLock.unlock();
1350         }
1351     }
1352 
1353     private void resetLoggerContext(LoggerContext cx) {
1354         Enumeration<String> enum_ = cx.getLoggerNames();
1355         while (enum_.hasMoreElements()) {
1356             String name = enum_.nextElement();
1357             Logger logger = cx.findLogger(name);
1358             if (logger != null) {
1359                 resetLogger(logger);
1360             }
1361         }
1362     }


1363 
1364     private void closeHandlers(Logger logger) {


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


1418         }
1419         return result.toArray(new String[result.size()]);
1420     }
1421 
1422     /**
1423      * Reinitialize the logging properties and reread the logging configuration
1424      * from the given stream, which should be in java.util.Properties format.
1425      * Any {@linkplain #addConfigurationListener registered configuration
1426      * listener} will be invoked after the properties are read.
1427      * <p>
1428      * Any log level definitions in the new configuration file will be
1429      * applied using Logger.setLevel(), if the target Logger exists.
1430      *
1431      * @param ins       stream to read properties from
1432      * @exception  SecurityException  if a security manager exists and if
1433      *             the caller does not have LoggingPermission("control").
1434      * @exception  IOException if there are problems reading from the stream.
1435      */
1436     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1437         checkPermission();

1438 
1439         // We don't want reset() and readConfiguration() to run
1440         // in parallel.
1441         configurationLock.lock();
1442         try {
1443             if (globalHandlersState == STATE_SHUTDOWN) {
1444                 // already in terminal state: don't even bother to read the
1445                 // configuration
1446                 return;
1447             }
1448 
1449             // reset configuration to STATE_INITIALIZING temporarily so that any
1450             // ongoing logging requests block in initializeGlobalHandlers()
1451             // and don't get processed while configuration is still changing
1452             reset(STATE_INITIALIZING);
1453             try {
1454                 try {
1455                     // Load the properties
1456                     props.load(ins);
1457                 } catch (IllegalArgumentException x) {
1458                     // props.load may throw an IllegalArgumentException if the stream
1459                     // contains malformed Unicode escape sequences.
1460                     // We wrap that in an IOException as readConfiguration is
1461                     // specified to throw IOException if there are problems reading
1462                     // from the stream.
1463                     // Note: new IOException(x.getMessage(), x) allow us to get a more
1464                     // concise error message than new IOException(x);
1465                     throw new IOException(x.getMessage(), x);
1466                 }
1467 
1468                 // Instantiate new configuration objects.
1469                 String names[] = parseClassNames("config");
1470 
1471                 for (String word : names) {
1472                     try {
1473                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1474                         clz.newInstance();
1475                     } catch (Exception ex) {
1476                         System.err.println("Can't load config class \"" + word + "\"");
1477                         System.err.println("" + ex);
1478                         // ex.printStackTrace();
1479                     }
1480                 }
1481 
1482                 // Set levels on any pre-existing loggers, based on the new properties.
1483                 setLevelsOnExistingLoggers();
1484 



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


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


1737             initializeGlobalHandlers();
1738             super.addHandler(h);
1739         }
1740 
1741         @Override
1742         public void removeHandler(Handler h) {
1743             initializeGlobalHandlers();
1744             super.removeHandler(h);
1745         }
1746 
1747         @Override
1748         Handler[] accessCheckedHandlers() {
1749             initializeGlobalHandlers();
1750             return super.accessCheckedHandlers();
1751         }
1752     }
1753 
1754 
1755     // Private method to be called when the configuration has
1756     // changed to apply any level settings to any pre-existing loggers.
1757     private void setLevelsOnExistingLoggers() {
1758         Enumeration<?> enum_ = props.propertyNames();
1759         while (enum_.hasMoreElements()) {
1760             String key = (String)enum_.nextElement();
1761             if (!key.endsWith(".level")) {
1762                 // Not a level definition.
1763                 continue;
1764             }
1765             int ix = key.length() - 6;
1766             String name = key.substring(0, ix);
1767             Level level = getLevelProperty(key, null);
1768             if (level == null) {
1769                 System.err.println("Bad level value for property: " + key);
1770                 continue;
1771             }
1772             for (LoggerContext cx : contexts()) {
1773                 Logger l = cx.findLogger(name);
1774                 if (l == null) {
1775                     continue;
1776                 }
1777                 l.setLevel(level);


< prev index next >