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 configurationLock.lock();
273 // temporarily block any ongoing logging requests until reset finishes
274 // by setting globalHandlersState to STATE_INITIALIZING
275 globalHandlersState = STATE_INITIALIZING;
276 try {
277 // Do a reset to close all active handlers which leaves state at
278 // STATE_INITIALIZING...
279 reset();
280 } finally {
281 // set globalHandlersState to a final STATE_SHUTDOWN so
282 // that no attempts will be made to initialize them again.
283 globalHandlersState = STATE_SHUTDOWN;
284 configurationLock.unlock();
285 }
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());
305 } catch (IllegalStateException e) {
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 // Since we are doing a reset we no longer want to initialize
1347 // the global handlers, if they haven't been initialized yet.
1348 // When globalHandlersState == STATE_INITIALIZING it means
1349 // we have been called from readConfiguration that is going to set
1350 // final state itself. Otherwise we set is to STATE_INITIALIZED.
1351 if (globalHandlersState != STATE_INITIALIZING) {
1352 globalHandlersState = STATE_INITIALIZED;
1353 }
1354
1355 for (LoggerContext cx : contexts()) {
1356 resetLoggerContext(cx);
1357 }
1358
1359 persistent.clear();
1360 } finally {
1361 configurationLock.unlock();
1362 }
1363 }
1364
1365 private void resetLoggerContext(LoggerContext cx) {
1366 Enumeration<String> enum_ = cx.getLoggerNames();
1367 while (enum_.hasMoreElements()) {
1368 String name = enum_.nextElement();
1369 Logger logger = cx.findLogger(name);
1370 if (logger != null) {
1371 resetLogger(logger);
1372 }
1373 }
1374 }
1375
1376 private void closeHandlers(Logger logger) {
1377 Handler[] targets = logger.getHandlers();
1378 for (Handler h : targets) {
1379 logger.removeHandler(h);
1380 try {
1381 h.close();
1382 } catch (Exception ex) {
1383 // Problems closing a handler? Keep going...
1384 }
1385 }
1386 }
1387
1388 // Private method to reset an individual target logger.
1389 private void resetLogger(Logger logger) {
1390 // Close all the Logger handlers.
1391 closeHandlers(logger);
1392
1393 // Reset Logger level
1394 String name = logger.getName();
1395 if (name != null && name.equals("")) {
1396 // This is the root logger.
1397 logger.setLevel(defaultLevel);
1398 } else {
1399 logger.setLevel(null);
1400 }
1401 }
1402
1403 // get a list of whitespace separated classnames from a property.
1404 private String[] parseClassNames(String propertyName) {
1405 String hands = getProperty(propertyName);
1406 if (hands == null) {
1407 return new String[0];
1408 }
1409 hands = hands.trim();
1410 int ix = 0;
1411 final List<String> result = new ArrayList<>();
1412 while (ix < hands.length()) {
1413 int end = ix;
1430 }
1431 return result.toArray(new String[result.size()]);
1432 }
1433
1434 /**
1435 * Reinitialize the logging properties and reread the logging configuration
1436 * from the given stream, which should be in java.util.Properties format.
1437 * Any {@linkplain #addConfigurationListener registered configuration
1438 * listener} will be invoked after the properties are read.
1439 * <p>
1440 * Any log level definitions in the new configuration file will be
1441 * applied using Logger.setLevel(), if the target Logger exists.
1442 *
1443 * @param ins stream to read properties from
1444 * @exception SecurityException if a security manager exists and if
1445 * the caller does not have LoggingPermission("control").
1446 * @exception IOException if there are problems reading from the stream.
1447 */
1448 public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1449 checkPermission();
1450
1451 // We don't want reset() and readConfiguration() to run
1452 // in parallel.
1453 configurationLock.lock();
1454 try {
1455 if (globalHandlersState == STATE_SHUTDOWN) {
1456 // already in terminal state: don't even bother to read the
1457 // configuration
1458 return;
1459 }
1460
1461 // change state to STATE_INITIALIZING so that reset() doesn't change it to
1462 // STATE_INITIALIZED just yet...
1463 globalHandlersState = STATE_INITIALIZING;
1464 try {
1465 // reset configuration which leaves globalHandlersState at STATE_INITIALIZING
1466 // so that while reading configuration, any ongoing logging requests block and
1467 // wait for the outcome (see the end of this try statement)
1468 reset();
1469
1470 try {
1471 // Load the properties
1472 props.load(ins);
1473 } catch (IllegalArgumentException x) {
1474 // props.load may throw an IllegalArgumentException if the stream
1475 // contains malformed Unicode escape sequences.
1476 // We wrap that in an IOException as readConfiguration is
1477 // specified to throw IOException if there are problems reading
1478 // from the stream.
1479 // Note: new IOException(x.getMessage(), x) allow us to get a more
1480 // concise error message than new IOException(x);
1481 throw new IOException(x.getMessage(), x);
1482 }
1483
1484 // Instantiate new configuration objects.
1485 String names[] = parseClassNames("config");
1486
1487 for (String word : names) {
1488 try {
1489 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
1490 clz.newInstance();
1491 } catch (Exception ex) {
1492 System.err.println("Can't load config class \"" + word + "\"");
1493 System.err.println("" + ex);
1494 // ex.printStackTrace();
1495 }
1496 }
1497
1498 // Set levels on any pre-existing loggers, based on the new properties.
1499 setLevelsOnExistingLoggers();
1500
1501 // Note that we need to reinitialize global handles when
1502 // they are first referenced.
1503 // Note: Marking global handlers as not initialized must be done
1504 // before unlocking.
1505 globalHandlersState = STATE_UNINITIALIZED;
1506 } catch (Throwable t) {
1507 // If there were any trouble, then set state to STATE_INITIALIZED
1508 // so that no global handlers reinitialization is performed on not fully
1509 // initialized configuration.
1510 globalHandlersState = STATE_INITIALIZED;
1511 // re-throw
1512 throw t;
1513 }
1514
1515 } finally {
1516 configurationLock.unlock();
1517 }
1518
1519 // should be called out of lock to avoid dead-lock situations
1520 // when user code is involved
1521 invokeConfigurationListeners();
1522 }
1523
1524 /**
1525 * Get the value of a logging property.
1526 * The method returns null if the property is not found.
1527 * @param name property name
1528 * @return property value
1529 */
1530 public String getProperty(String name) {
1531 return props.getProperty(name);
1532 }
1533
1534 // Package private method to get a String property.
1535 // If the property is not defined we return the given
1536 // default value.
1537 String getStringProperty(String name, String defaultValue) {
1538 String val = getProperty(name);
1539 if (val == null) {
1540 return defaultValue;
1541 }
1628 // we return the defaultValue.
1629 Formatter getFormatterProperty(String name, Formatter defaultValue) {
1630 String val = getProperty(name);
1631 try {
1632 if (val != null) {
1633 Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
1634 return (Formatter) clz.newInstance();
1635 }
1636 } catch (Exception ex) {
1637 // We got one of a variety of exceptions in creating the
1638 // class or creating an instance.
1639 // Drop through.
1640 }
1641 // We got an exception. Return the defaultValue.
1642 return defaultValue;
1643 }
1644
1645 // Private method to load the global handlers.
1646 // We do the real work lazily, when the global handlers
1647 // are first used.
1648 private void initializeGlobalHandlers() {
1649 int state = globalHandlersState;
1650 if (state == STATE_INITIALIZED || state == STATE_SHUTDOWN) {
1651 // Nothing to do: return.
1652 return;
1653 }
1654
1655 // If we have not initialized global handlers yet (or need to
1656 // reinitialize them), lets do it now (this case is indicated by
1657 // globalHandlersState == STATE_UNINITIALIZED).
1658 // If we are in the process of initializing global handlers we
1659 // also need to lock & wait (this case is indicated by
1660 // globalHandlersState == STATE_INITIALIZING).
1661 // So in either case we need to acquire the lock.
1662 configurationLock.lock();
1663 try {
1664 if (globalHandlersState != STATE_UNINITIALIZED) {
1665 return; // recursive call or nothing to do
1666 }
1667 // set globalHandlersState to STATE_INITIALIZING first to avoid
1668 // getting an infinite recursion when loadLoggerHandlers(...)
1669 // is going to call addHandler(...)
1670 globalHandlersState = STATE_INITIALIZING;
1671 try {
1672 loadLoggerHandlers(rootLogger, null, "handlers");
1673 } finally {
1674 globalHandlersState = STATE_INITIALIZED;
1675 }
1676 } finally {
1677 configurationLock.unlock();
1678 }
1679 }
1680
1681 static final Permission controlPermission = new LoggingPermission("control", null);
1682
1683 void checkPermission() {
1684 SecurityManager sm = System.getSecurityManager();
1685 if (sm != null)
1686 sm.checkPermission(controlPermission);
1687 }
1688
1689 /**
1690 * Check that the current context is trusted to modify the logging
1691 * configuration. This requires LoggingPermission("control").
1692 * <p>
1693 * If the check fails we throw a SecurityException, otherwise
1694 * we return normally.
1695 *
1696 * @exception SecurityException if a security manager exists and if
1697 * the caller does not have LoggingPermission("control").
1698 */
1753 initializeGlobalHandlers();
1754 super.addHandler(h);
1755 }
1756
1757 @Override
1758 public void removeHandler(Handler h) {
1759 initializeGlobalHandlers();
1760 super.removeHandler(h);
1761 }
1762
1763 @Override
1764 Handler[] accessCheckedHandlers() {
1765 initializeGlobalHandlers();
1766 return super.accessCheckedHandlers();
1767 }
1768 }
1769
1770
1771 // Private method to be called when the configuration has
1772 // changed to apply any level settings to any pre-existing loggers.
1773 private void setLevelsOnExistingLoggers() {
1774 Enumeration<?> enum_ = props.propertyNames();
1775 while (enum_.hasMoreElements()) {
1776 String key = (String)enum_.nextElement();
1777 if (!key.endsWith(".level")) {
1778 // Not a level definition.
1779 continue;
1780 }
1781 int ix = key.length() - 6;
1782 String name = key.substring(0, ix);
1783 Level level = getLevelProperty(key, null);
1784 if (level == null) {
1785 System.err.println("Bad level value for property: " + key);
1786 continue;
1787 }
1788 for (LoggerContext cx : contexts()) {
1789 Logger l = cx.findLogger(name);
1790 if (l == null) {
1791 continue;
1792 }
1793 l.setLevel(level);
|