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