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