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