LogManager.java 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. /* LogManager.java -- a class for maintaining Loggers and managing
  2. configuration properties
  3. Copyright (C) 2002, 2005, 2006, 2007 Free Software Foundation, Inc.
  4. This file is part of GNU Classpath.
  5. GNU Classpath is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9. GNU Classpath is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with GNU Classpath; see the file COPYING. If not, write to the
  15. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. 02110-1301 USA.
  17. Linking this library statically or dynamically with other modules is
  18. making a combined work based on this library. Thus, the terms and
  19. conditions of the GNU General Public License cover the whole
  20. combination.
  21. As a special exception, the copyright holders of this library give you
  22. permission to link this library with independent modules to produce an
  23. executable, regardless of the license terms of these independent
  24. modules, and to copy and distribute the resulting executable under
  25. terms of your choice, provided that you also meet, for each linked
  26. independent module, the terms and conditions of the license of that
  27. module. An independent module is a module which is not derived from
  28. or based on this library. If you modify this library, you may extend
  29. this exception to your version of the library, but you are not
  30. obligated to do so. If you do not wish to do so, delete this
  31. exception statement from your version. */
  32. package java.util.logging;
  33. import gnu.classpath.SystemProperties;
  34. import java.beans.PropertyChangeListener;
  35. import java.beans.PropertyChangeSupport;
  36. import java.io.ByteArrayInputStream;
  37. import java.io.IOException;
  38. import java.io.InputStream;
  39. import java.lang.ref.WeakReference;
  40. import java.net.URL;
  41. import java.util.Collections;
  42. import java.util.Enumeration;
  43. import java.util.HashMap;
  44. import java.util.Iterator;
  45. import java.util.List;
  46. import java.util.Map;
  47. import java.util.Properties;
  48. import java.util.StringTokenizer;
  49. /**
  50. * The <code>LogManager</code> maintains a hierarchical namespace
  51. * of Logger objects and manages properties for configuring the logging
  52. * framework. There exists only one single <code>LogManager</code>
  53. * per virtual machine. This instance can be retrieved using the
  54. * static method {@link #getLogManager()}.
  55. *
  56. * <p><strong>Configuration Process:</strong> The global LogManager
  57. * object is created and configured when the class
  58. * <code>java.util.logging.LogManager</code> is initialized.
  59. * The configuration process includes the subsequent steps:
  60. *
  61. * <ul>
  62. * <li>If the system property <code>java.util.logging.manager</code>
  63. * is set to the name of a subclass of
  64. * <code>java.util.logging.LogManager</code>, an instance of
  65. * that subclass is created and becomes the global LogManager.
  66. * Otherwise, a new instance of LogManager is created.</li>
  67. * <li>The <code>LogManager</code> constructor tries to create
  68. * a new instance of the class specified by the system
  69. * property <code>java.util.logging.config.class</code>.
  70. * Typically, the constructor of this class will call
  71. * <code>LogManager.getLogManager().readConfiguration(java.io.InputStream)</code>
  72. * for configuring the logging framework.
  73. * The configuration process stops at this point if
  74. * the system property <code>java.util.logging.config.class</code>
  75. * is set (irrespective of whether the class constructor
  76. * could be called or an exception was thrown).</li>
  77. *
  78. * <li>If the system property <code>java.util.logging.config.class</code>
  79. * is <em>not</em> set, the configuration parameters are read in from
  80. * a file and passed to
  81. * {@link #readConfiguration(java.io.InputStream)}.
  82. * The name and location of this file are specified by the system
  83. * property <code>java.util.logging.config.file</code>.</li>
  84. * <li>If the system property <code>java.util.logging.config.file</code>
  85. * is not set, however, the contents of the URL
  86. * "{gnu.classpath.home.url}/logging.properties" are passed to
  87. * {@link #readConfiguration(java.io.InputStream)}.
  88. * Here, "{gnu.classpath.home.url}" stands for the value of
  89. * the system property <code>gnu.classpath.home.url</code>.</li>
  90. * </ul>
  91. *
  92. * <p>The <code>LogManager</code> has a level of <code>INFO</code> by
  93. * default, and this will be inherited by <code>Logger</code>s unless they
  94. * override it either by properties or programmatically.
  95. *
  96. * @author Sascha Brawer (brawer@acm.org)
  97. */
  98. public class LogManager
  99. {
  100. /**
  101. * The object name for the logging management bean.
  102. * @since 1.5
  103. */
  104. public static final String LOGGING_MXBEAN_NAME
  105. = "java.util.logging:type=Logging";
  106. /**
  107. * The singleton LogManager instance.
  108. */
  109. private static LogManager logManager;
  110. /**
  111. * The singleton logging bean.
  112. */
  113. private static LoggingMXBean loggingBean;
  114. /**
  115. * The registered named loggers; maps the name of a Logger to
  116. * a WeakReference to it.
  117. */
  118. private Map<String, WeakReference<Logger>> loggers;
  119. /**
  120. * The properties for the logging framework which have been
  121. * read in last.
  122. */
  123. private Properties properties;
  124. /**
  125. * A delegate object that provides support for handling
  126. * PropertyChangeEvents. The API specification does not
  127. * mention which bean should be the source in the distributed
  128. * PropertyChangeEvents, but Mauve test code has determined that
  129. * the Sun J2SE 1.4 reference implementation uses the LogManager
  130. * class object. This is somewhat strange, as the class object
  131. * is not the bean with which listeners have to register, but
  132. * there is no reason for the GNU Classpath implementation to
  133. * behave differently from the reference implementation in
  134. * this case.
  135. */
  136. private final PropertyChangeSupport pcs = new PropertyChangeSupport( /* source bean */
  137. LogManager.class);
  138. protected LogManager()
  139. {
  140. loggers = new HashMap();
  141. }
  142. /**
  143. * Returns the globally shared LogManager instance.
  144. */
  145. public static synchronized LogManager getLogManager()
  146. {
  147. if (logManager == null)
  148. {
  149. logManager = makeLogManager();
  150. initLogManager();
  151. }
  152. return logManager;
  153. }
  154. private static final String MANAGER_PROPERTY = "java.util.logging.manager";
  155. private static LogManager makeLogManager()
  156. {
  157. String managerClassName = SystemProperties.getProperty(MANAGER_PROPERTY);
  158. LogManager manager = (LogManager) createInstance
  159. (managerClassName, LogManager.class, MANAGER_PROPERTY);
  160. if (manager == null)
  161. manager = new LogManager();
  162. return manager;
  163. }
  164. private static final String CONFIG_PROPERTY = "java.util.logging.config.class";
  165. private static void initLogManager()
  166. {
  167. LogManager manager = getLogManager();
  168. Logger.root.setLevel(Level.INFO);
  169. manager.addLogger(Logger.root);
  170. /* The Javadoc description of the class explains
  171. * what is going on here.
  172. */
  173. Object configurator = createInstance(System.getProperty(CONFIG_PROPERTY),
  174. /* must be instance of */ Object.class,
  175. CONFIG_PROPERTY);
  176. try
  177. {
  178. if (configurator == null)
  179. manager.readConfiguration();
  180. }
  181. catch (IOException ex)
  182. {
  183. /* FIXME: Is it ok to ignore exceptions here? */
  184. }
  185. }
  186. /**
  187. * Registers a listener which will be notified when the
  188. * logging properties are re-read.
  189. */
  190. public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  191. {
  192. /* do not register null. */
  193. listener.getClass();
  194. pcs.addPropertyChangeListener(listener);
  195. }
  196. /**
  197. * Unregisters a listener.
  198. *
  199. * If <code>listener</code> has not been registered previously,
  200. * nothing happens. Also, no exception is thrown if
  201. * <code>listener</code> is <code>null</code>.
  202. */
  203. public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  204. {
  205. if (listener != null)
  206. pcs.removePropertyChangeListener(listener);
  207. }
  208. /**
  209. * Adds a named logger. If a logger with the same name has
  210. * already been registered, the method returns <code>false</code>
  211. * without adding the logger.
  212. *
  213. * <p>The <code>LogManager</code> only keeps weak references
  214. * to registered loggers. Therefore, names can become available
  215. * after automatic garbage collection.
  216. *
  217. * @param logger the logger to be added.
  218. *
  219. * @return <code>true</code>if <code>logger</code> was added,
  220. * <code>false</code> otherwise.
  221. *
  222. * @throws NullPointerException if <code>name</code> is
  223. * <code>null</code>.
  224. */
  225. public synchronized boolean addLogger(Logger logger)
  226. {
  227. /* To developers thinking about to remove the 'synchronized'
  228. * declaration from this method: Please read the comment
  229. * in java.util.logging.Logger.getLogger(String, String)
  230. * and make sure that whatever you change wrt. synchronization
  231. * does not endanger thread-safety of Logger.getLogger.
  232. * The current implementation of Logger.getLogger assumes
  233. * that LogManager does its synchronization on the globally
  234. * shared instance of LogManager.
  235. */
  236. String name;
  237. WeakReference ref;
  238. /* This will throw a NullPointerException if logger is null,
  239. * as required by the API specification.
  240. */
  241. name = logger.getName();
  242. ref = loggers.get(name);
  243. if (ref != null)
  244. {
  245. if (ref.get() != null)
  246. return false;
  247. /* There has been a logger under this name in the past,
  248. * but it has been garbage collected.
  249. */
  250. loggers.remove(ref);
  251. }
  252. /* Adding a named logger requires a security permission. */
  253. if ((name != null) && ! name.equals(""))
  254. checkAccess();
  255. Logger parent = findAncestor(logger);
  256. loggers.put(name, new WeakReference<Logger>(logger));
  257. if (parent != logger.getParent())
  258. logger.setParent(parent);
  259. // The level of the newly added logger must be specified.
  260. // The easiest case is if there is a level for exactly this logger
  261. // in the properties. If no such level exists the level needs to be
  262. // searched along the hirachy. So if there is a new logger 'foo.blah.blub'
  263. // and an existing parent logger 'foo' the properties 'foo.blah.blub.level'
  264. // and 'foo.blah.level' need to be checked. If both do not exist in the
  265. // properties the level of the new logger is set to 'null' (i.e. it uses the
  266. // level of its parent 'foo').
  267. Level logLevel = logger.getLevel();
  268. String searchName = name;
  269. String parentName = parent != null ? parent.getName() : "";
  270. while (logLevel == null && ! searchName.equals(parentName))
  271. {
  272. logLevel = getLevelProperty(searchName + ".level", logLevel);
  273. int index = searchName.lastIndexOf('.');
  274. if(index > -1)
  275. searchName = searchName.substring(0,index);
  276. else
  277. searchName = "";
  278. }
  279. logger.setLevel(logLevel);
  280. /* It can happen that existing loggers should be children of
  281. * the newly added logger. For example, assume that there
  282. * already exist loggers under the names "", "foo", and "foo.bar.baz".
  283. * When adding "foo.bar", the logger "foo.bar.baz" should change
  284. * its parent to "foo.bar".
  285. */
  286. for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();)
  287. {
  288. Logger possChild = (Logger) ((WeakReference) loggers.get(iter.next()))
  289. .get();
  290. if ((possChild == null) || (possChild == logger)
  291. || (possChild.getParent() != parent))
  292. continue;
  293. if (! possChild.getName().startsWith(name))
  294. continue;
  295. if (possChild.getName().charAt(name.length()) != '.')
  296. continue;
  297. possChild.setParent(logger);
  298. }
  299. return true;
  300. }
  301. /**
  302. * Finds the closest ancestor for a logger among the currently
  303. * registered ones. For example, if the currently registered
  304. * loggers have the names "", "foo", and "foo.bar", the result for
  305. * "foo.bar.baz" will be the logger whose name is "foo.bar".
  306. *
  307. * @param child a logger for whose name no logger has been
  308. * registered.
  309. *
  310. * @return the closest ancestor for <code>child</code>,
  311. * or <code>null</code> if <code>child</code>
  312. * is the root logger.
  313. *
  314. * @throws NullPointerException if <code>child</code>
  315. * is <code>null</code>.
  316. */
  317. private synchronized Logger findAncestor(Logger child)
  318. {
  319. String childName = child.getName();
  320. int childNameLength = childName.length();
  321. Logger best = Logger.root;
  322. int bestNameLength = 0;
  323. Logger cand;
  324. int candNameLength;
  325. if (child == Logger.root)
  326. return null;
  327. for (String candName : loggers.keySet())
  328. {
  329. candNameLength = candName.length();
  330. if (candNameLength > bestNameLength
  331. && childNameLength > candNameLength
  332. && childName.startsWith(candName)
  333. && childName.charAt(candNameLength) == '.')
  334. {
  335. cand = loggers.get(candName).get();
  336. if ((cand == null) || (cand == child))
  337. continue;
  338. bestNameLength = candName.length();
  339. best = cand;
  340. }
  341. }
  342. return best;
  343. }
  344. /**
  345. * Returns a Logger given its name.
  346. *
  347. * @param name the name of the logger.
  348. *
  349. * @return a named Logger, or <code>null</code> if there is no
  350. * logger with that name.
  351. *
  352. * @throw java.lang.NullPointerException if <code>name</code>
  353. * is <code>null</code>.
  354. */
  355. public synchronized Logger getLogger(String name)
  356. {
  357. WeakReference<Logger> ref;
  358. /* Throw a NullPointerException if name is null. */
  359. name.getClass();
  360. ref = loggers.get(name);
  361. if (ref != null)
  362. return ref.get();
  363. else
  364. return null;
  365. }
  366. /**
  367. * Returns an Enumeration of currently registered Logger names.
  368. * Since other threads can register loggers at any time, the
  369. * result could be different any time this method is called.
  370. *
  371. * @return an Enumeration with the names of the currently
  372. * registered Loggers.
  373. */
  374. public synchronized Enumeration<String> getLoggerNames()
  375. {
  376. return Collections.enumeration(loggers.keySet());
  377. }
  378. /**
  379. * Resets the logging configuration by removing all handlers for
  380. * registered named loggers and setting their level to <code>null</code>.
  381. * The level of the root logger will be set to <code>Level.INFO</code>.
  382. *
  383. * @throws SecurityException if a security manager exists and
  384. * the caller is not granted the permission to control
  385. * the logging infrastructure.
  386. */
  387. public synchronized void reset() throws SecurityException
  388. {
  389. /* Throw a SecurityException if the caller does not have the
  390. * permission to control the logging infrastructure.
  391. */
  392. checkAccess();
  393. properties = new Properties();
  394. Iterator<WeakReference<Logger>> iter = loggers.values().iterator();
  395. while (iter.hasNext())
  396. {
  397. WeakReference<Logger> ref;
  398. Logger logger;
  399. ref = iter.next();
  400. if (ref != null)
  401. {
  402. logger = ref.get();
  403. if (logger == null)
  404. iter.remove();
  405. else if (logger != Logger.root)
  406. {
  407. logger.resetLogger();
  408. logger.setLevel(null);
  409. }
  410. }
  411. }
  412. Logger.root.setLevel(Level.INFO);
  413. Logger.root.resetLogger();
  414. }
  415. /**
  416. * Configures the logging framework by reading a configuration file.
  417. * The name and location of this file are specified by the system
  418. * property <code>java.util.logging.config.file</code>. If this
  419. * property is not set, the URL
  420. * "{gnu.classpath.home.url}/logging.properties" is taken, where
  421. * "{gnu.classpath.home.url}" stands for the value of the system
  422. * property <code>gnu.classpath.home.url</code>.
  423. *
  424. * <p>The task of configuring the framework is then delegated to
  425. * {@link #readConfiguration(java.io.InputStream)}, which will
  426. * notify registered listeners after having read the properties.
  427. *
  428. * @throws SecurityException if a security manager exists and
  429. * the caller is not granted the permission to control
  430. * the logging infrastructure, or if the caller is
  431. * not granted the permission to read the configuration
  432. * file.
  433. *
  434. * @throws IOException if there is a problem reading in the
  435. * configuration file.
  436. */
  437. public synchronized void readConfiguration()
  438. throws IOException, SecurityException
  439. {
  440. String path;
  441. InputStream inputStream;
  442. path = System.getProperty("java.util.logging.config.file");
  443. if ((path == null) || (path.length() == 0))
  444. {
  445. String url = (System.getProperty("gnu.classpath.home.url")
  446. + "/logging.properties");
  447. try
  448. {
  449. inputStream = new URL(url).openStream();
  450. }
  451. catch (Exception e)
  452. {
  453. inputStream=null;
  454. }
  455. // If no config file could be found use a default configuration.
  456. if(inputStream == null)
  457. {
  458. String defaultConfig = "handlers = java.util.logging.ConsoleHandler \n"
  459. + ".level=INFO \n";
  460. inputStream = new ByteArrayInputStream(defaultConfig.getBytes());
  461. }
  462. }
  463. else
  464. inputStream = new java.io.FileInputStream(path);
  465. try
  466. {
  467. readConfiguration(inputStream);
  468. }
  469. finally
  470. {
  471. // Close the stream in order to save
  472. // resources such as file descriptors.
  473. inputStream.close();
  474. }
  475. }
  476. public synchronized void readConfiguration(InputStream inputStream)
  477. throws IOException, SecurityException
  478. {
  479. Properties newProperties;
  480. Enumeration keys;
  481. checkAccess();
  482. newProperties = new Properties();
  483. newProperties.load(inputStream);
  484. reset();
  485. this.properties = newProperties;
  486. keys = newProperties.propertyNames();
  487. while (keys.hasMoreElements())
  488. {
  489. String key = ((String) keys.nextElement()).trim();
  490. String value = newProperties.getProperty(key);
  491. if (value == null)
  492. continue;
  493. value = value.trim();
  494. if ("handlers".equals(key))
  495. {
  496. // In Java 5 and earlier this was specified to be
  497. // whitespace-separated, but in reality it also accepted
  498. // commas (tomcat relied on this), and in Java 6 the
  499. // documentation was updated to fit the implementation.
  500. StringTokenizer tokenizer = new StringTokenizer(value,
  501. " \t\n\r\f,");
  502. while (tokenizer.hasMoreTokens())
  503. {
  504. String handlerName = tokenizer.nextToken();
  505. Handler handler = (Handler)
  506. createInstance(handlerName, Handler.class, key);
  507. // Tomcat also relies on the implementation ignoring
  508. // items in 'handlers' which are not class names.
  509. if (handler != null)
  510. Logger.root.addHandler(handler);
  511. }
  512. }
  513. if (key.endsWith(".level"))
  514. {
  515. String loggerName = key.substring(0, key.length() - 6);
  516. Logger logger = getLogger(loggerName);
  517. if (logger == null)
  518. {
  519. logger = Logger.getLogger(loggerName);
  520. addLogger(logger);
  521. }
  522. Level level = null;
  523. try
  524. {
  525. level = Level.parse(value);
  526. }
  527. catch (IllegalArgumentException e)
  528. {
  529. warn("bad level \'" + value + "\'", e);
  530. }
  531. if (level != null)
  532. {
  533. logger.setLevel(level);
  534. }
  535. continue;
  536. }
  537. }
  538. /* The API specification does not talk about the
  539. * property name that is distributed with the
  540. * PropertyChangeEvent. With test code, it could
  541. * be determined that the Sun J2SE 1.4 reference
  542. * implementation uses null for the property name.
  543. */
  544. pcs.firePropertyChange(null, null, null);
  545. }
  546. /**
  547. * Returns the value of a configuration property as a String.
  548. */
  549. public synchronized String getProperty(String name)
  550. {
  551. if (properties != null)
  552. return properties.getProperty(name);
  553. else
  554. return null;
  555. }
  556. /**
  557. * Returns the value of a configuration property as an integer.
  558. * This function is a helper used by the Classpath implementation
  559. * of java.util.logging, it is <em>not</em> specified in the
  560. * logging API.
  561. *
  562. * @param name the name of the configuration property.
  563. *
  564. * @param defaultValue the value that will be returned if the
  565. * property is not defined, or if its value is not an integer
  566. * number.
  567. */
  568. static int getIntProperty(String name, int defaultValue)
  569. {
  570. try
  571. {
  572. return Integer.parseInt(getLogManager().getProperty(name));
  573. }
  574. catch (Exception ex)
  575. {
  576. return defaultValue;
  577. }
  578. }
  579. /**
  580. * Returns the value of a configuration property as an integer,
  581. * provided it is inside the acceptable range.
  582. * This function is a helper used by the Classpath implementation
  583. * of java.util.logging, it is <em>not</em> specified in the
  584. * logging API.
  585. *
  586. * @param name the name of the configuration property.
  587. *
  588. * @param minValue the lowest acceptable value.
  589. *
  590. * @param maxValue the highest acceptable value.
  591. *
  592. * @param defaultValue the value that will be returned if the
  593. * property is not defined, or if its value is not an integer
  594. * number, or if it is less than the minimum value,
  595. * or if it is greater than the maximum value.
  596. */
  597. static int getIntPropertyClamped(String name, int defaultValue,
  598. int minValue, int maxValue)
  599. {
  600. int val = getIntProperty(name, defaultValue);
  601. if ((val < minValue) || (val > maxValue))
  602. val = defaultValue;
  603. return val;
  604. }
  605. /**
  606. * Returns the value of a configuration property as a boolean.
  607. * This function is a helper used by the Classpath implementation
  608. * of java.util.logging, it is <em>not</em> specified in the
  609. * logging API.
  610. *
  611. * @param name the name of the configuration property.
  612. *
  613. * @param defaultValue the value that will be returned if the
  614. * property is not defined, or if its value is neither
  615. * <code>"true"</code> nor <code>"false"</code>.
  616. */
  617. static boolean getBooleanProperty(String name, boolean defaultValue)
  618. {
  619. try
  620. {
  621. return (Boolean.valueOf(getLogManager().getProperty(name))).booleanValue();
  622. }
  623. catch (Exception ex)
  624. {
  625. return defaultValue;
  626. }
  627. }
  628. /**
  629. * Returns the value of a configuration property as a Level.
  630. * This function is a helper used by the Classpath implementation
  631. * of java.util.logging, it is <em>not</em> specified in the
  632. * logging API.
  633. *
  634. * @param propertyName the name of the configuration property.
  635. *
  636. * @param defaultValue the value that will be returned if the
  637. * property is not defined, or if
  638. * {@link Level#parse(java.lang.String)} does not like
  639. * the property value.
  640. */
  641. static Level getLevelProperty(String propertyName, Level defaultValue)
  642. {
  643. try
  644. {
  645. String value = getLogManager().getProperty(propertyName);
  646. if (value != null)
  647. return Level.parse(getLogManager().getProperty(propertyName));
  648. else
  649. return defaultValue;
  650. }
  651. catch (Exception ex)
  652. {
  653. return defaultValue;
  654. }
  655. }
  656. /**
  657. * Returns the value of a configuration property as a Class.
  658. * This function is a helper used by the Classpath implementation
  659. * of java.util.logging, it is <em>not</em> specified in the
  660. * logging API.
  661. *
  662. * @param propertyName the name of the configuration property.
  663. *
  664. * @param defaultValue the value that will be returned if the
  665. * property is not defined, or if it does not specify
  666. * the name of a loadable class.
  667. */
  668. static final Class getClassProperty(String propertyName, Class defaultValue)
  669. {
  670. String propertyValue = logManager.getProperty(propertyName);
  671. if (propertyValue != null)
  672. try
  673. {
  674. return locateClass(propertyValue);
  675. }
  676. catch (ClassNotFoundException e)
  677. {
  678. warn(propertyName + " = " + propertyValue, e);
  679. }
  680. return defaultValue;
  681. }
  682. static final Object getInstanceProperty(String propertyName, Class ofClass,
  683. Class defaultClass)
  684. {
  685. Class klass = getClassProperty(propertyName, defaultClass);
  686. if (klass == null)
  687. return null;
  688. try
  689. {
  690. Object obj = klass.newInstance();
  691. if (ofClass.isInstance(obj))
  692. return obj;
  693. }
  694. catch (InstantiationException e)
  695. {
  696. warn(propertyName + " = " + klass.getName(), e);
  697. }
  698. catch (IllegalAccessException e)
  699. {
  700. warn(propertyName + " = " + klass.getName(), e);
  701. }
  702. if (defaultClass == null)
  703. return null;
  704. try
  705. {
  706. return defaultClass.newInstance();
  707. }
  708. catch (java.lang.InstantiationException ex)
  709. {
  710. throw new RuntimeException(ex.getMessage());
  711. }
  712. catch (java.lang.IllegalAccessException ex)
  713. {
  714. throw new RuntimeException(ex.getMessage());
  715. }
  716. }
  717. /**
  718. * An instance of <code>LoggingPermission("control")</code>
  719. * that is shared between calls to <code>checkAccess()</code>.
  720. */
  721. private static final LoggingPermission controlPermission = new LoggingPermission("control",
  722. null);
  723. /**
  724. * Checks whether the current security context allows changing
  725. * the configuration of the logging framework. For the security
  726. * context to be trusted, it has to be granted
  727. * a LoggingPermission("control").
  728. *
  729. * @throws SecurityException if a security manager exists and
  730. * the caller is not granted the permission to control
  731. * the logging infrastructure.
  732. */
  733. public void checkAccess() throws SecurityException
  734. {
  735. SecurityManager sm = System.getSecurityManager();
  736. if (sm != null)
  737. sm.checkPermission(controlPermission);
  738. }
  739. /**
  740. * Creates a new instance of a class specified by name and verifies
  741. * that it is an instance (or subclass of) a given type.
  742. *
  743. * @param className the name of the class of which a new instance
  744. * should be created.
  745. *
  746. * @param type the object created must be an instance of
  747. * <code>type</code> or any subclass of <code>type</code>
  748. *
  749. * @param property the system property to reference in error
  750. * messages
  751. *
  752. * @return the new instance, or <code>null</code> if
  753. * <code>className</code> is <code>null</code>, if no class
  754. * with that name could be found, if there was an error
  755. * loading that class, or if the constructor of the class
  756. * has thrown an exception.
  757. */
  758. private static final Object createInstance(String className, Class type,
  759. String property)
  760. {
  761. Class klass = null;
  762. if ((className == null) || (className.length() == 0))
  763. return null;
  764. try
  765. {
  766. klass = locateClass(className);
  767. if (type.isAssignableFrom(klass))
  768. return klass.newInstance();
  769. warn(property, className, "not an instance of " + type.getName());
  770. }
  771. catch (ClassNotFoundException e)
  772. {
  773. warn(property, className, "class not found", e);
  774. }
  775. catch (IllegalAccessException e)
  776. {
  777. warn(property, className, "illegal access", e);
  778. }
  779. catch (InstantiationException e)
  780. {
  781. warn(property, className, e);
  782. }
  783. catch (java.lang.LinkageError e)
  784. {
  785. warn(property, className, "linkage error", e);
  786. }
  787. return null;
  788. }
  789. private static final void warn(String property, String klass, Throwable t)
  790. {
  791. warn(property, klass, null, t);
  792. }
  793. private static final void warn(String property, String klass, String msg)
  794. {
  795. warn(property, klass, msg, null);
  796. }
  797. private static final void warn(String property, String klass, String msg,
  798. Throwable t)
  799. {
  800. warn("error instantiating '" + klass + "' referenced by " + property +
  801. (msg == null ? "" : ", " + msg), t);
  802. }
  803. /**
  804. * All debug warnings go through this method.
  805. */
  806. private static final void warn(String msg, Throwable t)
  807. {
  808. System.err.println("WARNING: " + msg);
  809. if (t != null)
  810. t.printStackTrace(System.err);
  811. }
  812. /**
  813. * Locates a class by first checking the system class loader and
  814. * then checking the context class loader.
  815. *
  816. * @param name the fully qualified name of the Class to locate
  817. * @return Class the located Class
  818. */
  819. private static Class locateClass(String name) throws ClassNotFoundException
  820. {
  821. // GCJ LOCAL
  822. // Unfortunately this can be called during bootstrap when
  823. // Thread.currentThread() will return null.
  824. // See bug #27658
  825. Thread t = Thread.currentThread();
  826. ClassLoader loader = (t == null) ? null : t.getContextClassLoader();
  827. try
  828. {
  829. return Class.forName(name, true, loader);
  830. }
  831. catch (ClassNotFoundException e)
  832. {
  833. loader = ClassLoader.getSystemClassLoader();
  834. return Class.forName(name, true, loader);
  835. }
  836. }
  837. /**
  838. * Return the logging bean. There is a single logging bean per
  839. * VM instance.
  840. * @since 1.5
  841. */
  842. public static synchronized LoggingMXBean getLoggingMXBean()
  843. {
  844. if (loggingBean == null)
  845. {
  846. loggingBean = new LoggingMXBean()
  847. {
  848. public String getLoggerLevel(String logger)
  849. {
  850. LogManager mgr = getLogManager();
  851. Logger l = mgr.getLogger(logger);
  852. if (l == null)
  853. return null;
  854. Level lev = l.getLevel();
  855. if (lev == null)
  856. return "";
  857. return lev.getName();
  858. }
  859. public List getLoggerNames()
  860. {
  861. LogManager mgr = getLogManager();
  862. // This is inefficient, but perhaps better for maintenance.
  863. return Collections.list(mgr.getLoggerNames());
  864. }
  865. public String getParentLoggerName(String logger)
  866. {
  867. LogManager mgr = getLogManager();
  868. Logger l = mgr.getLogger(logger);
  869. if (l == null)
  870. return null;
  871. l = l.getParent();
  872. if (l == null)
  873. return "";
  874. return l.getName();
  875. }
  876. public void setLoggerLevel(String logger, String level)
  877. {
  878. LogManager mgr = getLogManager();
  879. Logger l = mgr.getLogger(logger);
  880. if (l == null)
  881. throw new IllegalArgumentException("no logger named " + logger);
  882. Level newLevel;
  883. if (level == null)
  884. newLevel = null;
  885. else
  886. newLevel = Level.parse(level);
  887. l.setLevel(newLevel);
  888. }
  889. };
  890. }
  891. return loggingBean;
  892. }
  893. }