Source for java.util.logging.LogManager

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