Source Code Cross Referenced for LogFactory.java in  » Library » apache-common-Logging » org » apache » commons » logging » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » apache common Logging » org.apache.commons.logging 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2001-2006 The Apache Software Foundation.
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         * 
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:
0017:        package org.apache.commons.logging;
0018:
0019:        import java.io.BufferedReader;
0020:        import java.io.FileOutputStream;
0021:        import java.io.IOException;
0022:        import java.io.InputStream;
0023:        import java.io.InputStreamReader;
0024:        import java.io.PrintStream;
0025:        import java.lang.reflect.InvocationTargetException;
0026:        import java.lang.reflect.Method;
0027:        import java.net.URL;
0028:        import java.security.AccessController;
0029:        import java.security.PrivilegedAction;
0030:        import java.util.Enumeration;
0031:        import java.util.Hashtable;
0032:        import java.util.Properties;
0033:
0034:        /**
0035:         * <p>Factory for creating {@link Log} instances, with discovery and
0036:         * configuration features similar to that employed by standard Java APIs
0037:         * such as JAXP.</p>
0038:         * 
0039:         * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily
0040:         * based on the SAXParserFactory and DocumentBuilderFactory implementations
0041:         * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.</p>
0042:         *
0043:         * @author Craig R. McClanahan
0044:         * @author Costin Manolache
0045:         * @author Richard A. Sitze
0046:         * @version $Revision: 399431 $ $Date: 2006-05-03 21:58:34 +0100 (Wed, 03 May 2006) $
0047:         */
0048:
0049:        public abstract class LogFactory {
0050:
0051:            // ----------------------------------------------------- Manifest Constants
0052:
0053:            /**
0054:             * The name (<code>priority</code>) of the key in the config file used to 
0055:             * specify the priority of that particular config file. The associated value 
0056:             * is a floating-point number; higher values take priority over lower values.
0057:             */
0058:            public static final String PRIORITY_KEY = "priority";
0059:
0060:            /**
0061:             * The name (<code>use_tccl</code>) of the key in the config file used 
0062:             * to specify whether logging classes should be loaded via the thread 
0063:             * context class loader (TCCL), or not. By default, the TCCL is used.
0064:             */
0065:            public static final String TCCL_KEY = "use_tccl";
0066:
0067:            /**
0068:             * The name (<code>org.apache.commons.logging.LogFactory</code>) of the property 
0069:             * used to identify the LogFactory implementation
0070:             * class name. This can be used as a system property, or as an entry in a
0071:             * configuration properties file.
0072:             */
0073:            public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
0074:
0075:            /**
0076:             * The fully qualified class name of the fallback <code>LogFactory</code>
0077:             * implementation class to use, if no other can be found.
0078:             */
0079:            public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.LogFactoryImpl";
0080:
0081:            /**
0082:             * The name (<code>commons-logging.properties</code>) of the properties file to search for.
0083:             */
0084:            public static final String FACTORY_PROPERTIES = "commons-logging.properties";
0085:
0086:            /**
0087:             * JDK1.3+ <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider">
0088:             * 'Service Provider' specification</a>.
0089:             * 
0090:             */
0091:            protected static final String SERVICE_ID = "META-INF/services/org.apache.commons.logging.LogFactory";
0092:
0093:            /**
0094:             * The name (<code>org.apache.commons.logging.diagnostics.dest</code>) 
0095:             * of the property used to enable internal commons-logging
0096:             * diagnostic output, in order to get information on what logging
0097:             * implementations are being discovered, what classloaders they 
0098:             * are loaded through, etc.
0099:             * <p>
0100:             * If a system property of this name is set then the value is
0101:             * assumed to be the name of a file. The special strings
0102:             * STDOUT or STDERR (case-sensitive) indicate output to
0103:             * System.out and System.err respectively.
0104:             * <p>
0105:             * Diagnostic logging should be used only to debug problematic
0106:             * configurations and should not be set in normal production use.
0107:             */
0108:            public static final String DIAGNOSTICS_DEST_PROPERTY = "org.apache.commons.logging.diagnostics.dest";
0109:
0110:            /**
0111:             * When null (the usual case), no diagnostic output will be
0112:             * generated by LogFactory or LogFactoryImpl. When non-null,
0113:             * interesting events will be written to the specified object.
0114:             */
0115:            private static PrintStream diagnosticsStream = null;
0116:
0117:            /**
0118:             * A string that gets prefixed to every message output by the
0119:             * logDiagnostic method, so that users can clearly see which
0120:             * LogFactory class is generating the output.
0121:             */
0122:            private static String diagnosticPrefix;
0123:
0124:            /**
0125:             * <p>Setting this system property 
0126:             * (<code>org.apache.commons.logging.LogFactory.HashtableImpl</code>) 
0127:             * value allows the <code>Hashtable</code> used to store
0128:             * classloaders to be substituted by an alternative implementation.
0129:             * </p>
0130:             * <p>
0131:             * <strong>Note:</strong> <code>LogFactory</code> will print:
0132:             * <code><pre>
0133:             * [ERROR] LogFactory: Load of custom hashtable failed</em>
0134:             * </pre></code>
0135:             * to system error and then continue using a standard Hashtable.
0136:             * </p>
0137:             * <p>
0138:             * <strong>Usage:</strong> Set this property when Java is invoked
0139:             * and <code>LogFactory</code> will attempt to load a new instance 
0140:             * of the given implementation class.
0141:             * For example, running the following ant scriplet:
0142:             * <code><pre>
0143:             *  &lt;java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}"&gt;
0144:             *     ...
0145:             *     &lt;sysproperty 
0146:             *        key="org.apache.commons.logging.LogFactory.HashtableImpl"
0147:             *        value="org.apache.commons.logging.AltHashtable"/&gt;
0148:             *  &lt;/java&gt;
0149:             * </pre></code>
0150:             * will mean that <code>LogFactory</code> will load an instance of
0151:             * <code>org.apache.commons.logging.AltHashtable</code>.
0152:             * </p>
0153:             * <p>
0154:             * A typical use case is to allow a custom
0155:             * Hashtable implementation using weak references to be substituted.
0156:             * This will allow classloaders to be garbage collected without
0157:             * the need to release them (on 1.3+ JVMs only, of course ;)
0158:             * </p>
0159:             */
0160:            public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = "org.apache.commons.logging.LogFactory.HashtableImpl";
0161:            /** Name used to load the weak hashtable implementation by names */
0162:            private static final String WEAK_HASHTABLE_CLASSNAME = "org.apache.commons.logging.impl.WeakHashtable";
0163:
0164:            /**
0165:             * A reference to the classloader that loaded this class. This is the
0166:             * same as LogFactory.class.getClassLoader(). However computing this
0167:             * value isn't quite as simple as that, as we potentially need to use
0168:             * AccessControllers etc. It's more efficient to compute it once and
0169:             * cache it here.
0170:             */
0171:            private static ClassLoader this ClassLoader;
0172:
0173:            // ----------------------------------------------------------- Constructors
0174:
0175:            /**
0176:             * Protected constructor that is not available for public use.
0177:             */
0178:            protected LogFactory() {
0179:            }
0180:
0181:            // --------------------------------------------------------- Public Methods
0182:
0183:            /**
0184:             * Return the configuration attribute with the specified name (if any),
0185:             * or <code>null</code> if there is no such attribute.
0186:             *
0187:             * @param name Name of the attribute to return
0188:             */
0189:            public abstract Object getAttribute(String name);
0190:
0191:            /**
0192:             * Return an array containing the names of all currently defined
0193:             * configuration attributes.  If there are no such attributes, a zero
0194:             * length array is returned.
0195:             */
0196:            public abstract String[] getAttributeNames();
0197:
0198:            /**
0199:             * Convenience method to derive a name from the specified class and
0200:             * call <code>getInstance(String)</code> with it.
0201:             *
0202:             * @param clazz Class for which a suitable Log name will be derived
0203:             *
0204:             * @exception LogConfigurationException if a suitable <code>Log</code>
0205:             *  instance cannot be returned
0206:             */
0207:            public abstract Log getInstance(Class clazz)
0208:                    throws LogConfigurationException;
0209:
0210:            /**
0211:             * <p>Construct (if necessary) and return a <code>Log</code> instance,
0212:             * using the factory's current set of configuration attributes.</p>
0213:             *
0214:             * <p><strong>NOTE</strong> - Depending upon the implementation of
0215:             * the <code>LogFactory</code> you are using, the <code>Log</code>
0216:             * instance you are returned may or may not be local to the current
0217:             * application, and may or may not be returned again on a subsequent
0218:             * call with the same name argument.</p>
0219:             *
0220:             * @param name Logical name of the <code>Log</code> instance to be
0221:             *  returned (the meaning of this name is only known to the underlying
0222:             *  logging implementation that is being wrapped)
0223:             *
0224:             * @exception LogConfigurationException if a suitable <code>Log</code>
0225:             *  instance cannot be returned
0226:             */
0227:            public abstract Log getInstance(String name)
0228:                    throws LogConfigurationException;
0229:
0230:            /**
0231:             * Release any internal references to previously created {@link Log}
0232:             * instances returned by this factory.  This is useful in environments
0233:             * like servlet containers, which implement application reloading by
0234:             * throwing away a ClassLoader.  Dangling references to objects in that
0235:             * class loader would prevent garbage collection.
0236:             */
0237:            public abstract void release();
0238:
0239:            /**
0240:             * Remove any configuration attribute associated with the specified name.
0241:             * If there is no such attribute, no action is taken.
0242:             *
0243:             * @param name Name of the attribute to remove
0244:             */
0245:            public abstract void removeAttribute(String name);
0246:
0247:            /**
0248:             * Set the configuration attribute with the specified name.  Calling
0249:             * this with a <code>null</code> value is equivalent to calling
0250:             * <code>removeAttribute(name)</code>.
0251:             *
0252:             * @param name Name of the attribute to set
0253:             * @param value Value of the attribute to set, or <code>null</code>
0254:             *  to remove any setting for this attribute
0255:             */
0256:            public abstract void setAttribute(String name, Object value);
0257:
0258:            // ------------------------------------------------------- Static Variables
0259:
0260:            /**
0261:             * The previously constructed <code>LogFactory</code> instances, keyed by
0262:             * the <code>ClassLoader</code> with which it was created.
0263:             */
0264:            protected static Hashtable factories = null;
0265:
0266:            /**
0267:             * Prevously constructed <code>LogFactory</code> instance as in the
0268:             * <code>factories</code> map, but for the case where
0269:             * <code>getClassLoader</code> returns <code>null</code>.
0270:             * This can happen when:
0271:             * <ul>
0272:             * <li>using JDK1.1 and the calling code is loaded via the system
0273:             *  classloader (very common)</li>
0274:             * <li>using JDK1.2+ and the calling code is loaded via the boot
0275:             *  classloader (only likely for embedded systems work).</li>
0276:             * </ul>
0277:             * Note that <code>factories</code> is a <i>Hashtable</i> (not a HashMap),
0278:             * and hashtables don't allow null as a key.
0279:             */
0280:            protected static LogFactory nullClassLoaderFactory = null;
0281:
0282:            /**
0283:             * Create the hashtable which will be used to store a map of
0284:             * (context-classloader -> logfactory-object). Version 1.2+ of Java
0285:             * supports "weak references", allowing a custom Hashtable class
0286:             * to be used which uses only weak references to its keys. Using weak
0287:             * references can fix memory leaks on webapp unload in some cases (though
0288:             * not all). Version 1.1 of Java does not support weak references, so we
0289:             * must dynamically determine which we are using. And just for fun, this
0290:             * code also supports the ability for a system property to specify an
0291:             * arbitrary Hashtable implementation name.
0292:             * <p>
0293:             * Note that the correct way to ensure no memory leaks occur is to ensure
0294:             * that LogFactory.release(contextClassLoader) is called whenever a 
0295:             * webapp is undeployed.
0296:             */
0297:            private static final Hashtable createFactoryStore() {
0298:                Hashtable result = null;
0299:                String storeImplementationClass = System
0300:                        .getProperty(HASHTABLE_IMPLEMENTATION_PROPERTY);
0301:                if (storeImplementationClass == null) {
0302:                    storeImplementationClass = WEAK_HASHTABLE_CLASSNAME;
0303:                }
0304:                try {
0305:                    Class implementationClass = Class
0306:                            .forName(storeImplementationClass);
0307:                    result = (Hashtable) implementationClass.newInstance();
0308:
0309:                } catch (Throwable t) {
0310:                    // ignore
0311:                    if (!WEAK_HASHTABLE_CLASSNAME
0312:                            .equals(storeImplementationClass)) {
0313:                        // if the user's trying to set up a custom implementation, give a clue
0314:                        if (isDiagnosticsEnabled()) {
0315:                            // use internal logging to issue the warning
0316:                            logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed");
0317:                        } else {
0318:                            // we *really* want this output, even if diagnostics weren't
0319:                            // explicitly enabled by the user.
0320:                            System.err
0321:                                    .println("[ERROR] LogFactory: Load of custom hashtable failed");
0322:                        }
0323:                    }
0324:                }
0325:                if (result == null) {
0326:                    result = new Hashtable();
0327:                }
0328:                return result;
0329:            }
0330:
0331:            // --------------------------------------------------------- Static Methods
0332:
0333:            /**
0334:             * <p>Construct (if necessary) and return a <code>LogFactory</code>
0335:             * instance, using the following ordered lookup procedure to determine
0336:             * the name of the implementation class to be loaded.</p>
0337:             * <ul>
0338:             * <li>The <code>org.apache.commons.logging.LogFactory</code> system
0339:             *     property.</li>
0340:             * <li>The JDK 1.3 Service Discovery mechanism</li>
0341:             * <li>Use the properties file <code>commons-logging.properties</code>
0342:             *     file, if found in the class path of this class.  The configuration
0343:             *     file is in standard <code>java.util.Properties</code> format and
0344:             *     contains the fully qualified name of the implementation class
0345:             *     with the key being the system property defined above.</li>
0346:             * <li>Fall back to a default implementation class
0347:             *     (<code>org.apache.commons.logging.impl.LogFactoryImpl</code>).</li>
0348:             * </ul>
0349:             *
0350:             * <p><em>NOTE</em> - If the properties file method of identifying the
0351:             * <code>LogFactory</code> implementation class is utilized, all of the
0352:             * properties defined in this file will be set as configuration attributes
0353:             * on the corresponding <code>LogFactory</code> instance.</p>
0354:             * 
0355:             * <p><em>NOTE</em> - In a multithreaded environment it is possible 
0356:             * that two different instances will be returned for the same 
0357:             * classloader environment. 
0358:             * </p>
0359:             *
0360:             * @exception LogConfigurationException if the implementation class is not
0361:             *  available or cannot be instantiated.
0362:             */
0363:            public static LogFactory getFactory()
0364:                    throws LogConfigurationException {
0365:                // Identify the class loader we will be using
0366:                ClassLoader contextClassLoader = getContextClassLoader();
0367:
0368:                if (contextClassLoader == null) {
0369:                    // This is an odd enough situation to report about. This
0370:                    // output will be a nuisance on JDK1.1, as the system
0371:                    // classloader is null in that environment.
0372:                    if (isDiagnosticsEnabled()) {
0373:                        logDiagnostic("Context classloader is null.");
0374:                    }
0375:                }
0376:
0377:                // Return any previously registered factory for this class loader
0378:                LogFactory factory = getCachedFactory(contextClassLoader);
0379:                if (factory != null) {
0380:                    return factory;
0381:                }
0382:
0383:                if (isDiagnosticsEnabled()) {
0384:                    logDiagnostic("[LOOKUP] LogFactory implementation requested for the first time for context classloader "
0385:                            + objectId(contextClassLoader));
0386:                    logHierarchy("[LOOKUP] ", contextClassLoader);
0387:                }
0388:
0389:                // Load properties file.
0390:                //
0391:                // If the properties file exists, then its contents are used as
0392:                // "attributes" on the LogFactory implementation class. One particular
0393:                // property may also control which LogFactory concrete subclass is
0394:                // used, but only if other discovery mechanisms fail..
0395:                //
0396:                // As the properties file (if it exists) will be used one way or 
0397:                // another in the end we may as well look for it first.
0398:
0399:                Properties props = getConfigurationFile(contextClassLoader,
0400:                        FACTORY_PROPERTIES);
0401:
0402:                // Determine whether we will be using the thread context class loader to
0403:                // load logging classes or not by checking the loaded properties file (if any).
0404:                ClassLoader baseClassLoader = contextClassLoader;
0405:                if (props != null) {
0406:                    String useTCCLStr = props.getProperty(TCCL_KEY);
0407:                    if (useTCCLStr != null) {
0408:                        // The Boolean.valueOf(useTCCLStr).booleanValue() formulation
0409:                        // is required for Java 1.2 compatability.
0410:                        if (Boolean.valueOf(useTCCLStr).booleanValue() == false) {
0411:                            // Don't use current context classloader when locating any
0412:                            // LogFactory or Log classes, just use the class that loaded
0413:                            // this abstract class. When this class is deployed in a shared
0414:                            // classpath of a container, it means webapps cannot deploy their
0415:                            // own logging implementations. It also means that it is up to the
0416:                            // implementation whether to load library-specific config files
0417:                            // from the TCCL or not.
0418:                            baseClassLoader = this ClassLoader;
0419:                        }
0420:                    }
0421:                }
0422:
0423:                // Determine which concrete LogFactory subclass to use.
0424:                // First, try a global system property
0425:                if (isDiagnosticsEnabled()) {
0426:                    logDiagnostic("[LOOKUP] Looking for system property ["
0427:                            + FACTORY_PROPERTY
0428:                            + "] to define the LogFactory subclass to use...");
0429:                }
0430:
0431:                try {
0432:                    String factoryClass = System.getProperty(FACTORY_PROPERTY);
0433:                    if (factoryClass != null) {
0434:                        if (isDiagnosticsEnabled()) {
0435:                            logDiagnostic("[LOOKUP] Creating an instance of LogFactory class '"
0436:                                    + factoryClass
0437:                                    + "' as specified by system property "
0438:                                    + FACTORY_PROPERTY);
0439:                        }
0440:
0441:                        factory = newFactory(factoryClass, baseClassLoader,
0442:                                contextClassLoader);
0443:                    } else {
0444:                        if (isDiagnosticsEnabled()) {
0445:                            logDiagnostic("[LOOKUP] No system property ["
0446:                                    + FACTORY_PROPERTY + "] defined.");
0447:                        }
0448:                    }
0449:                } catch (SecurityException e) {
0450:                    if (isDiagnosticsEnabled()) {
0451:                        logDiagnostic("[LOOKUP] A security exception occurred while trying to create an"
0452:                                + " instance of the custom factory class"
0453:                                + ": ["
0454:                                + e.getMessage().trim()
0455:                                + "]. Trying alternative implementations...");
0456:                    }
0457:                    ; // ignore
0458:                } catch (RuntimeException e) {
0459:                    // This is not consistent with the behaviour when a bad LogFactory class is
0460:                    // specified in a services file.
0461:                    //
0462:                    // One possible exception that can occur here is a ClassCastException when
0463:                    // the specified class wasn't castable to this LogFactory type.
0464:                    if (isDiagnosticsEnabled()) {
0465:                        logDiagnostic("[LOOKUP] An exception occurred while trying to create an"
0466:                                + " instance of the custom factory class"
0467:                                + ": ["
0468:                                + e.getMessage().trim()
0469:                                + "] as specified by a system property.");
0470:                    }
0471:                    throw e;
0472:                }
0473:
0474:                // Second, try to find a service by using the JDK1.3 class
0475:                // discovery mechanism, which involves putting a file with the name
0476:                // of an interface class in the META-INF/services directory, where the
0477:                // contents of the file is a single line specifying a concrete class 
0478:                // that implements the desired interface.
0479:
0480:                if (factory == null) {
0481:                    if (isDiagnosticsEnabled()) {
0482:                        logDiagnostic("[LOOKUP] Looking for a resource file of name ["
0483:                                + SERVICE_ID
0484:                                + "] to define the LogFactory subclass to use...");
0485:                    }
0486:                    try {
0487:                        InputStream is = getResourceAsStream(
0488:                                contextClassLoader, SERVICE_ID);
0489:
0490:                        if (is != null) {
0491:                            // This code is needed by EBCDIC and other strange systems.
0492:                            // It's a fix for bugs reported in xerces
0493:                            BufferedReader rd;
0494:                            try {
0495:                                rd = new BufferedReader(new InputStreamReader(
0496:                                        is, "UTF-8"));
0497:                            } catch (java.io.UnsupportedEncodingException e) {
0498:                                rd = new BufferedReader(new InputStreamReader(
0499:                                        is));
0500:                            }
0501:
0502:                            String factoryClassName = rd.readLine();
0503:                            rd.close();
0504:
0505:                            if (factoryClassName != null
0506:                                    && !"".equals(factoryClassName)) {
0507:                                if (isDiagnosticsEnabled()) {
0508:                                    logDiagnostic("[LOOKUP]  Creating an instance of LogFactory class "
0509:                                            + factoryClassName
0510:                                            + " as specified by file '"
0511:                                            + SERVICE_ID
0512:                                            + "' which was present in the path of the context"
0513:                                            + " classloader.");
0514:                                }
0515:                                factory = newFactory(factoryClassName,
0516:                                        baseClassLoader, contextClassLoader);
0517:                            }
0518:                        } else {
0519:                            // is == null
0520:                            if (isDiagnosticsEnabled()) {
0521:                                logDiagnostic("[LOOKUP] No resource file with name '"
0522:                                        + SERVICE_ID + "' found.");
0523:                            }
0524:                        }
0525:                    } catch (Exception ex) {
0526:                        // note: if the specified LogFactory class wasn't compatible with LogFactory
0527:                        // for some reason, a ClassCastException will be caught here, and attempts will
0528:                        // continue to find a compatible class.
0529:                        if (isDiagnosticsEnabled()) {
0530:                            logDiagnostic("[LOOKUP] A security exception occurred while trying to create an"
0531:                                    + " instance of the custom factory class"
0532:                                    + ": ["
0533:                                    + ex.getMessage().trim()
0534:                                    + "]. Trying alternative implementations...");
0535:                        }
0536:                        ; // ignore
0537:                    }
0538:                }
0539:
0540:                // Third try looking into the properties file read earlier (if found)
0541:
0542:                if (factory == null) {
0543:                    if (props != null) {
0544:                        if (isDiagnosticsEnabled()) {
0545:                            logDiagnostic("[LOOKUP] Looking in properties file for entry with key '"
0546:                                    + FACTORY_PROPERTY
0547:                                    + "' to define the LogFactory subclass to use...");
0548:                        }
0549:                        String factoryClass = props
0550:                                .getProperty(FACTORY_PROPERTY);
0551:                        if (factoryClass != null) {
0552:                            if (isDiagnosticsEnabled()) {
0553:                                logDiagnostic("[LOOKUP] Properties file specifies LogFactory subclass '"
0554:                                        + factoryClass + "'");
0555:                            }
0556:                            factory = newFactory(factoryClass, baseClassLoader,
0557:                                    contextClassLoader);
0558:
0559:                            // TODO: think about whether we need to handle exceptions from newFactory
0560:                        } else {
0561:                            if (isDiagnosticsEnabled()) {
0562:                                logDiagnostic("[LOOKUP] Properties file has no entry specifying LogFactory subclass.");
0563:                            }
0564:                        }
0565:                    } else {
0566:                        if (isDiagnosticsEnabled()) {
0567:                            logDiagnostic("[LOOKUP] No properties file available to determine"
0568:                                    + " LogFactory subclass from..");
0569:                        }
0570:                    }
0571:                }
0572:
0573:                // Fourth, try the fallback implementation class
0574:
0575:                if (factory == null) {
0576:                    if (isDiagnosticsEnabled()) {
0577:                        logDiagnostic("[LOOKUP] Loading the default LogFactory implementation '"
0578:                                + FACTORY_DEFAULT
0579:                                + "' via the same classloader that loaded this LogFactory"
0580:                                + " class (ie not looking in the context classloader).");
0581:                    }
0582:
0583:                    // Note: unlike the above code which can try to load custom LogFactory
0584:                    // implementations via the TCCL, we don't try to load the default LogFactory
0585:                    // implementation via the context classloader because:
0586:                    // * that can cause problems (see comments in newFactory method)
0587:                    // * no-one should be customising the code of the default class
0588:                    // Yes, we do give up the ability for the child to ship a newer
0589:                    // version of the LogFactoryImpl class and have it used dynamically
0590:                    // by an old LogFactory class in the parent, but that isn't 
0591:                    // necessarily a good idea anyway.
0592:                    factory = newFactory(FACTORY_DEFAULT, this ClassLoader,
0593:                            contextClassLoader);
0594:                }
0595:
0596:                if (factory != null) {
0597:                    /**
0598:                     * Always cache using context class loader.
0599:                     */
0600:                    cacheFactory(contextClassLoader, factory);
0601:
0602:                    if (props != null) {
0603:                        Enumeration names = props.propertyNames();
0604:                        while (names.hasMoreElements()) {
0605:                            String name = (String) names.nextElement();
0606:                            String value = props.getProperty(name);
0607:                            factory.setAttribute(name, value);
0608:                        }
0609:                    }
0610:                }
0611:
0612:                return factory;
0613:            }
0614:
0615:            /**
0616:             * Convenience method to return a named logger, without the application
0617:             * having to care about factories.
0618:             *
0619:             * @param clazz Class from which a log name will be derived
0620:             *
0621:             * @exception LogConfigurationException if a suitable <code>Log</code>
0622:             *  instance cannot be returned
0623:             */
0624:            public static Log getLog(Class clazz)
0625:                    throws LogConfigurationException {
0626:
0627:                return (getFactory().getInstance(clazz));
0628:
0629:            }
0630:
0631:            /**
0632:             * Convenience method to return a named logger, without the application
0633:             * having to care about factories.
0634:             *
0635:             * @param name Logical name of the <code>Log</code> instance to be
0636:             *  returned (the meaning of this name is only known to the underlying
0637:             *  logging implementation that is being wrapped)
0638:             *
0639:             * @exception LogConfigurationException if a suitable <code>Log</code>
0640:             *  instance cannot be returned
0641:             */
0642:            public static Log getLog(String name)
0643:                    throws LogConfigurationException {
0644:
0645:                return (getFactory().getInstance(name));
0646:
0647:            }
0648:
0649:            /**
0650:             * Release any internal references to previously created {@link LogFactory}
0651:             * instances that have been associated with the specified class loader
0652:             * (if any), after calling the instance method <code>release()</code> on
0653:             * each of them.
0654:             *
0655:             * @param classLoader ClassLoader for which to release the LogFactory
0656:             */
0657:            public static void release(ClassLoader classLoader) {
0658:
0659:                if (isDiagnosticsEnabled()) {
0660:                    logDiagnostic("Releasing factory for classloader "
0661:                            + objectId(classLoader));
0662:                }
0663:                synchronized (factories) {
0664:                    if (classLoader == null) {
0665:                        if (nullClassLoaderFactory != null) {
0666:                            nullClassLoaderFactory.release();
0667:                            nullClassLoaderFactory = null;
0668:                        }
0669:                    } else {
0670:                        LogFactory factory = (LogFactory) factories
0671:                                .get(classLoader);
0672:                        if (factory != null) {
0673:                            factory.release();
0674:                            factories.remove(classLoader);
0675:                        }
0676:                    }
0677:                }
0678:
0679:            }
0680:
0681:            /**
0682:             * Release any internal references to previously created {@link LogFactory}
0683:             * instances, after calling the instance method <code>release()</code> on
0684:             * each of them.  This is useful in environments like servlet containers,
0685:             * which implement application reloading by throwing away a ClassLoader.
0686:             * Dangling references to objects in that class loader would prevent
0687:             * garbage collection.
0688:             */
0689:            public static void releaseAll() {
0690:
0691:                if (isDiagnosticsEnabled()) {
0692:                    logDiagnostic("Releasing factory for all classloaders.");
0693:                }
0694:                synchronized (factories) {
0695:                    Enumeration elements = factories.elements();
0696:                    while (elements.hasMoreElements()) {
0697:                        LogFactory element = (LogFactory) elements
0698:                                .nextElement();
0699:                        element.release();
0700:                    }
0701:                    factories.clear();
0702:
0703:                    if (nullClassLoaderFactory != null) {
0704:                        nullClassLoaderFactory.release();
0705:                        nullClassLoaderFactory = null;
0706:                    }
0707:                }
0708:
0709:            }
0710:
0711:            // ------------------------------------------------------ Protected Methods
0712:
0713:            /**
0714:             * Safely get access to the classloader for the specified class.
0715:             * <p>
0716:             * Theoretically, calling getClassLoader can throw a security exception,
0717:             * and so should be done under an AccessController in order to provide
0718:             * maximum flexibility. However in practice people don't appear to use
0719:             * security policies that forbid getClassLoader calls. So for the moment
0720:             * all code is written to call this method rather than Class.getClassLoader,
0721:             * so that we could put AccessController stuff in this method without any
0722:             * disruption later if we need to.
0723:             * <p>
0724:             * Even when using an AccessController, however, this method can still
0725:             * throw SecurityException. Commons-logging basically relies on the
0726:             * ability to access classloaders, ie a policy that forbids all
0727:             * classloader access will also prevent commons-logging from working: 
0728:             * currently this method will throw an exception preventing the entire app
0729:             * from starting up. Maybe it would be good to detect this situation and
0730:             * just disable all commons-logging? Not high priority though - as stated
0731:             * above, security policies that prevent classloader access aren't common.
0732:             * 
0733:             * @since 1.1
0734:             */
0735:            protected static ClassLoader getClassLoader(Class clazz) {
0736:                try {
0737:                    return clazz.getClassLoader();
0738:                } catch (SecurityException ex) {
0739:                    if (isDiagnosticsEnabled()) {
0740:                        logDiagnostic("Unable to get classloader for class '"
0741:                                + clazz + "' due to security restrictions - "
0742:                                + ex.getMessage());
0743:                    }
0744:                    throw ex;
0745:                }
0746:            }
0747:
0748:            /**
0749:             * Calls LogFactory.directGetContextClassLoader under the control of an
0750:             * AccessController class. This means that java code running under a
0751:             * security manager that forbids access to ClassLoaders will still work
0752:             * if this class is given appropriate privileges, even when the caller
0753:             * doesn't have such privileges. Without using an AccessController, the
0754:             * the entire call stack must have the privilege before the call is
0755:             * allowed.
0756:             *  
0757:             * @return the context classloader associated with the current thread,
0758:             * or null if security doesn't allow it.
0759:             * 
0760:             * @throws LogConfigurationException if there was some weird error while
0761:             * attempting to get the context classloader.
0762:             * 
0763:             * @throws SecurityException if the current java security policy doesn't
0764:             * allow this class to access the context classloader.
0765:             */
0766:            protected static ClassLoader getContextClassLoader()
0767:                    throws LogConfigurationException {
0768:
0769:                return (ClassLoader) AccessController
0770:                        .doPrivileged(new PrivilegedAction() {
0771:                            public Object run() {
0772:                                return directGetContextClassLoader();
0773:                            }
0774:                        });
0775:            }
0776:
0777:            /**
0778:             * Return the thread context class loader if available; otherwise return 
0779:             * null. 
0780:             * <p>
0781:             * Most/all code should call getContextClassLoader rather than calling
0782:             * this method directly.
0783:             * <p>
0784:             * The thread context class loader is available for JDK 1.2
0785:             * or later, if certain security conditions are met.
0786:             * <p>
0787:             * Note that no internal logging is done within this method because
0788:             * this method is called every time LogFactory.getLogger() is called,
0789:             * and we don't want too much output generated here.
0790:             * 
0791:             * @exception LogConfigurationException if a suitable class loader
0792:             * cannot be identified.
0793:             * 
0794:             * @exception SecurityException if the java security policy forbids
0795:             * access to the context classloader from one of the classes in the
0796:             * current call stack. 
0797:             * @since 1.1
0798:             */
0799:            protected static ClassLoader directGetContextClassLoader()
0800:                    throws LogConfigurationException {
0801:                ClassLoader classLoader = null;
0802:
0803:                try {
0804:                    // Are we running on a JDK 1.2 or later system?
0805:                    Method method = Thread.class.getMethod(
0806:                            "getContextClassLoader", (Class[]) null);
0807:
0808:                    // Get the thread context class loader (if there is one)
0809:                    try {
0810:                        classLoader = (ClassLoader) method.invoke(Thread
0811:                                .currentThread(), (Object[]) null);
0812:                    } catch (IllegalAccessException e) {
0813:                        throw new LogConfigurationException(
0814:                                "Unexpected IllegalAccessException", e);
0815:                    } catch (InvocationTargetException e) {
0816:                        /**
0817:                         * InvocationTargetException is thrown by 'invoke' when
0818:                         * the method being invoked (getContextClassLoader) throws
0819:                         * an exception.
0820:                         *
0821:                         * getContextClassLoader() throws SecurityException when
0822:                         * the context class loader isn't an ancestor of the
0823:                         * calling class's class loader, or if security
0824:                         * permissions are restricted.
0825:                         *
0826:                         * In the first case (not related), we want to ignore and
0827:                         * keep going.  We cannot help but also ignore the second
0828:                         * with the logic below, but other calls elsewhere (to
0829:                         * obtain a class loader) will trigger this exception where
0830:                         * we can make a distinction.
0831:                         */
0832:                        if (e.getTargetException() instanceof  SecurityException) {
0833:                            ; // ignore
0834:                        } else {
0835:                            // Capture 'e.getTargetException()' exception for details
0836:                            // alternate: log 'e.getTargetException()', and pass back 'e'.
0837:                            throw new LogConfigurationException(
0838:                                    "Unexpected InvocationTargetException", e
0839:                                            .getTargetException());
0840:                        }
0841:                    }
0842:                } catch (NoSuchMethodException e) {
0843:                    // Assume we are running on JDK 1.1
0844:                    classLoader = getClassLoader(LogFactory.class);
0845:
0846:                    // We deliberately don't log a message here to outputStream;
0847:                    // this message would be output for every call to LogFactory.getLog()
0848:                    // when running on JDK1.1
0849:                    //
0850:                    // if (outputStream != null) {
0851:                    //    outputStream.println(
0852:                    //        "Method Thread.getContextClassLoader does not exist;"
0853:                    //         + " assuming this is JDK 1.1, and that the context"
0854:                    //         + " classloader is the same as the class that loaded"
0855:                    //         + " the concrete LogFactory class.");
0856:                    // }
0857:
0858:                }
0859:
0860:                // Return the selected class loader
0861:                return classLoader;
0862:            }
0863:
0864:            /**
0865:             * Check cached factories (keyed by contextClassLoader)
0866:             *
0867:             * @param contextClassLoader is the context classloader associated
0868:             * with the current thread. This allows separate LogFactory objects
0869:             * per component within a container, provided each component has
0870:             * a distinct context classloader set. This parameter may be null
0871:             * in JDK1.1, and in embedded systems where jcl-using code is
0872:             * placed in the bootclasspath.
0873:             * 
0874:             * @return the factory associated with the specified classloader if
0875:             * one has previously been created, or null if this is the first time
0876:             * we have seen this particular classloader.
0877:             */
0878:            private static LogFactory getCachedFactory(
0879:                    ClassLoader contextClassLoader) {
0880:                LogFactory factory = null;
0881:
0882:                if (contextClassLoader == null) {
0883:                    // We have to handle this specially, as factories is a Hashtable
0884:                    // and those don't accept null as a key value.
0885:                    //
0886:                    // nb: nullClassLoaderFactory might be null. That's ok.
0887:                    factory = nullClassLoaderFactory;
0888:                } else {
0889:                    factory = (LogFactory) factories.get(contextClassLoader);
0890:                }
0891:
0892:                return factory;
0893:            }
0894:
0895:            /**
0896:             * Remember this factory, so later calls to LogFactory.getCachedFactory
0897:             * can return the previously created object (together with all its
0898:             * cached Log objects).
0899:             *
0900:             * @param classLoader should be the current context classloader. Note that
0901:             * this can be null under some circumstances; this is ok.
0902:             *
0903:             * @param factory should be the factory to cache. This should never be null.
0904:             */
0905:            private static void cacheFactory(ClassLoader classLoader,
0906:                    LogFactory factory) {
0907:                // Ideally we would assert(factory != null) here. However reporting
0908:                // errors from within a logging implementation is a little tricky!
0909:
0910:                if (factory != null) {
0911:                    if (classLoader == null) {
0912:                        nullClassLoaderFactory = factory;
0913:                    } else {
0914:                        factories.put(classLoader, factory);
0915:                    }
0916:                }
0917:            }
0918:
0919:            /**
0920:             * Return a new instance of the specified <code>LogFactory</code>
0921:             * implementation class, loaded by the specified class loader.
0922:             * If that fails, try the class loader used to load this
0923:             * (abstract) LogFactory.
0924:             * <p>
0925:             * <h2>ClassLoader conflicts</h2>
0926:             * Note that there can be problems if the specified ClassLoader is not the 
0927:             * same as the classloader that loaded this class, ie when loading a
0928:             * concrete LogFactory subclass via a context classloader.
0929:             * <p>
0930:             * The problem is the same one that can occur when loading a concrete Log
0931:             * subclass via a context classloader.
0932:             * <p>
0933:             * The problem occurs when code running in the context classloader calls
0934:             * class X which was loaded via a parent classloader, and class X then calls
0935:             * LogFactory.getFactory (either directly or via LogFactory.getLog). Because
0936:             * class X was loaded via the parent, it binds to LogFactory loaded via
0937:             * the parent. When the code in this method finds some LogFactoryYYYY
0938:             * class in the child (context) classloader, and there also happens to be a
0939:             * LogFactory class defined in the child classloader, then LogFactoryYYYY
0940:             * will be bound to LogFactory@childloader. It cannot be cast to
0941:             * LogFactory@parentloader, ie this method cannot return the object as
0942:             * the desired type. Note that it doesn't matter if the LogFactory class
0943:             * in the child classloader is identical to the LogFactory class in the
0944:             * parent classloader, they are not compatible.
0945:             * <p>
0946:             * The solution taken here is to simply print out an error message when
0947:             * this occurs then throw an exception. The deployer of the application
0948:             * must ensure they remove all occurrences of the LogFactory class from
0949:             * the child classloader in order to resolve the issue. Note that they
0950:             * do not have to move the custom LogFactory subclass; that is ok as
0951:             * long as the only LogFactory class it can find to bind to is in the
0952:             * parent classloader.
0953:             * <p>
0954:             * @param factoryClass Fully qualified name of the <code>LogFactory</code>
0955:             *  implementation class
0956:             * @param classLoader ClassLoader from which to load this class
0957:             * @param contextClassLoader is the context that this new factory will
0958:             * manage logging for.
0959:             *
0960:             * @exception LogConfigurationException if a suitable instance
0961:             *  cannot be created
0962:             * @since 1.1
0963:             */
0964:            protected static LogFactory newFactory(final String factoryClass,
0965:                    final ClassLoader classLoader,
0966:                    final ClassLoader contextClassLoader)
0967:                    throws LogConfigurationException {
0968:                // Note that any unchecked exceptions thrown by the createFactory
0969:                // method will propagate out of this method; in particular a
0970:                // ClassCastException can be thrown.
0971:                Object result = AccessController
0972:                        .doPrivileged(new PrivilegedAction() {
0973:                            public Object run() {
0974:                                return createFactory(factoryClass, classLoader);
0975:                            }
0976:                        });
0977:
0978:                if (result instanceof  LogConfigurationException) {
0979:                    LogConfigurationException ex = (LogConfigurationException) result;
0980:                    if (isDiagnosticsEnabled()) {
0981:                        logDiagnostic("An error occurred while loading the factory class:"
0982:                                + ex.getMessage());
0983:                    }
0984:                    throw ex;
0985:                }
0986:                if (isDiagnosticsEnabled()) {
0987:                    logDiagnostic("Created object " + objectId(result)
0988:                            + " to manage classloader "
0989:                            + objectId(contextClassLoader));
0990:                }
0991:                return (LogFactory) result;
0992:            }
0993:
0994:            /**
0995:             * Method provided for backwards compatibility; see newFactory version that
0996:             * takes 3 parameters.
0997:             * <p>
0998:             * This method would only ever be called in some rather odd situation.
0999:             * Note that this method is static, so overriding in a subclass doesn't
1000:             * have any effect unless this method is called from a method in that
1001:             * subclass. However this method only makes sense to use from the
1002:             * getFactory method, and as that is almost always invoked via
1003:             * LogFactory.getFactory, any custom definition in a subclass would be
1004:             * pointless. Only a class with a custom getFactory method, then invoked
1005:             * directly via CustomFactoryImpl.getFactory or similar would ever call
1006:             * this. Anyway, it's here just in case, though the "managed class loader"
1007:             * value output to the diagnostics will not report the correct value.
1008:             */
1009:            protected static LogFactory newFactory(final String factoryClass,
1010:                    final ClassLoader classLoader) {
1011:                return newFactory(factoryClass, classLoader, null);
1012:            }
1013:
1014:            /**
1015:             * Implements the operations described in the javadoc for newFactory.
1016:             * 
1017:             * @param factoryClass
1018:             * 
1019:             * @param classLoader used to load the specified factory class. This is
1020:             * expected to be either the TCCL or the classloader which loaded this
1021:             * class. Note that the classloader which loaded this class might be
1022:             * "null" (ie the bootloader) for embedded systems.
1023:             * 
1024:             * @return either a LogFactory object or a LogConfigurationException object.
1025:             * @since 1.1
1026:             */
1027:            protected static Object createFactory(String factoryClass,
1028:                    ClassLoader classLoader) {
1029:
1030:                // This will be used to diagnose bad configurations
1031:                // and allow a useful message to be sent to the user
1032:                Class logFactoryClass = null;
1033:                try {
1034:                    if (classLoader != null) {
1035:                        try {
1036:                            // First the given class loader param (thread class loader)
1037:
1038:                            // Warning: must typecast here & allow exception
1039:                            // to be generated/caught & recast properly.
1040:                            logFactoryClass = classLoader
1041:                                    .loadClass(factoryClass);
1042:                            if (LogFactory.class
1043:                                    .isAssignableFrom(logFactoryClass)) {
1044:                                if (isDiagnosticsEnabled()) {
1045:                                    logDiagnostic("Loaded class "
1046:                                            + logFactoryClass.getName()
1047:                                            + " from classloader "
1048:                                            + objectId(classLoader));
1049:                                }
1050:                            } else {
1051:                                //
1052:                                // This indicates a problem with the ClassLoader tree.
1053:                                // An incompatible ClassLoader was used to load the 
1054:                                // implementation. 
1055:                                // As the same classes
1056:                                // must be available in multiple class loaders,
1057:                                // it is very likely that multiple JCL jars are present.
1058:                                // The most likely fix for this
1059:                                // problem is to remove the extra JCL jars from the 
1060:                                // ClassLoader hierarchy. 
1061:                                //
1062:                                if (isDiagnosticsEnabled()) {
1063:                                    logDiagnostic("Factory class "
1064:                                            + logFactoryClass.getName()
1065:                                            + " loaded from classloader "
1066:                                            + objectId(logFactoryClass
1067:                                                    .getClassLoader())
1068:                                            + " does not extend '"
1069:                                            + LogFactory.class.getName()
1070:                                            + "' as loaded by this classloader.");
1071:                                    logHierarchy("[BAD CL TREE] ", classLoader);
1072:                                }
1073:                            }
1074:
1075:                            return (LogFactory) logFactoryClass.newInstance();
1076:
1077:                        } catch (ClassNotFoundException ex) {
1078:                            if (classLoader == this ClassLoader) {
1079:                                // Nothing more to try, onwards.
1080:                                if (isDiagnosticsEnabled()) {
1081:                                    logDiagnostic("Unable to locate any class called '"
1082:                                            + factoryClass
1083:                                            + "' via classloader "
1084:                                            + objectId(classLoader));
1085:                                }
1086:                                throw ex;
1087:                            }
1088:                            // ignore exception, continue
1089:                        } catch (NoClassDefFoundError e) {
1090:                            if (classLoader == this ClassLoader) {
1091:                                // Nothing more to try, onwards.
1092:                                if (isDiagnosticsEnabled()) {
1093:                                    logDiagnostic("Class '"
1094:                                            + factoryClass
1095:                                            + "' cannot be loaded"
1096:                                            + " via classloader "
1097:                                            + objectId(classLoader)
1098:                                            + " - it depends on some other class that cannot"
1099:                                            + " be found.");
1100:                                }
1101:                                throw e;
1102:                            }
1103:                            // ignore exception, continue
1104:                        } catch (ClassCastException e) {
1105:                            if (classLoader == this ClassLoader) {
1106:                                // There's no point in falling through to the code below that
1107:                                // tries again with thisClassLoader, because we've just tried
1108:                                // loading with that loader (not the TCCL). Just throw an
1109:                                // appropriate exception here.
1110:
1111:                                final boolean implements LogFactory = implements LogFactory(logFactoryClass);
1112:
1113:                                //
1114:                                // Construct a good message: users may not actual expect that a custom implementation 
1115:                                // has been specified. Several well known containers use this mechanism to adapt JCL 
1116:                                // to their native logging system. 
1117:                                // 
1118:                                String msg = "The application has specified that a custom LogFactory implementation should be used but "
1119:                                        + "Class '"
1120:                                        + factoryClass
1121:                                        + "' cannot be converted to '"
1122:                                        + LogFactory.class.getName() + "'. ";
1123:                                if (implements LogFactory) {
1124:                                    msg = msg
1125:                                            + "The conflict is caused by the presence of multiple LogFactory classes in incompatible classloaders. "
1126:                                            + "Background can be found in http://jakarta.apache.org/commons/logging/tech.html. "
1127:                                            + "If you have not explicitly specified a custom LogFactory then it is likely that "
1128:                                            + "the container has set one without your knowledge. "
1129:                                            + "In this case, consider using the commons-logging-adapters.jar file or "
1130:                                            + "specifying the standard LogFactory from the command line. ";
1131:                                } else {
1132:                                    msg = msg
1133:                                            + "Please check the custom implementation. ";
1134:                                }
1135:                                msg = msg
1136:                                        + "Help can be found @http://jakarta.apache.org/commons/logging/troubleshooting.html.";
1137:
1138:                                if (isDiagnosticsEnabled()) {
1139:                                    logDiagnostic(msg);
1140:                                }
1141:
1142:                                ClassCastException ex = new ClassCastException(
1143:                                        msg);
1144:                                throw ex;
1145:                            }
1146:
1147:                            // Ignore exception, continue. Presumably the classloader was the
1148:                            // TCCL; the code below will try to load the class via thisClassLoader.
1149:                            // This will handle the case where the original calling class is in
1150:                            // a shared classpath but the TCCL has a copy of LogFactory and the
1151:                            // specified LogFactory implementation; we will fall back to using the
1152:                            // LogFactory implementation from the same classloader as this class.
1153:                            //
1154:                            // Issue: this doesn't handle the reverse case, where this LogFactory
1155:                            // is in the webapp, and the specified LogFactory implementation is
1156:                            // in a shared classpath. In that case:
1157:                            // (a) the class really does implement LogFactory (bad log msg above)
1158:                            // (b) the fallback code will result in exactly the same problem.
1159:                        }
1160:                    }
1161:
1162:                    /* At this point, either classLoader == null, OR
1163:                     * classLoader was unable to load factoryClass.
1164:                     *
1165:                     * In either case, we call Class.forName, which is equivalent
1166:                     * to LogFactory.class.getClassLoader().load(name), ie we ignore
1167:                     * the classloader parameter the caller passed, and fall back
1168:                     * to trying the classloader associated with this class. See the
1169:                     * javadoc for the newFactory method for more info on the 
1170:                     * consequences of this.
1171:                     *
1172:                     * Notes:
1173:                     * * LogFactory.class.getClassLoader() may return 'null'
1174:                     *   if LogFactory is loaded by the bootstrap classloader.
1175:                     */
1176:                    // Warning: must typecast here & allow exception
1177:                    // to be generated/caught & recast properly.
1178:                    if (isDiagnosticsEnabled()) {
1179:                        logDiagnostic("Unable to load factory class via classloader "
1180:                                + objectId(classLoader)
1181:                                + " - trying the classloader associated with this LogFactory.");
1182:                    }
1183:                    logFactoryClass = Class.forName(factoryClass);
1184:                    return (LogFactory) logFactoryClass.newInstance();
1185:                } catch (Exception e) {
1186:                    // Check to see if we've got a bad configuration
1187:                    if (isDiagnosticsEnabled()) {
1188:                        logDiagnostic("Unable to create LogFactory instance.");
1189:                    }
1190:                    if (logFactoryClass != null
1191:                            && !LogFactory.class
1192:                                    .isAssignableFrom(logFactoryClass)) {
1193:
1194:                        return new LogConfigurationException(
1195:                                "The chosen LogFactory implementation does not extend LogFactory."
1196:                                        + " Please check your configuration.",
1197:                                e);
1198:                    }
1199:                    return new LogConfigurationException(e);
1200:                }
1201:            }
1202:
1203:            /**
1204:             * Determines whether the given class actually implements <code>LogFactory</code>.
1205:             * Diagnostic information is also logged.
1206:             * <p>
1207:             * <strong>Usage:</strong> to diagnose whether a classloader conflict is the cause
1208:             * of incompatibility. The test used is whether the class is assignable from
1209:             * the <code>LogFactory</code> class loaded by the class's classloader.
1210:             * @param logFactoryClass <code>Class</code> which may implement <code>LogFactory</code>
1211:             * @return true if the <code>logFactoryClass</code> does extend
1212:             * <code>LogFactory</code> when that class is loaded via the same
1213:             * classloader that loaded the <code>logFactoryClass</code>.
1214:             */
1215:            private static boolean implements LogFactory(Class logFactoryClass) {
1216:                boolean implements LogFactory = false;
1217:                if (logFactoryClass != null) {
1218:                    try {
1219:                        ClassLoader logFactoryClassLoader = logFactoryClass
1220:                                .getClassLoader();
1221:                        if (logFactoryClassLoader == null) {
1222:                            logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader");
1223:                        } else {
1224:                            logHierarchy("[CUSTOM LOG FACTORY] ",
1225:                                    logFactoryClassLoader);
1226:                            Class factoryFromCustomLoader = Class.forName(
1227:                                    "org.apache.commons.logging.LogFactory",
1228:                                    false, logFactoryClassLoader);
1229:                            implements LogFactory = factoryFromCustomLoader
1230:                                    .isAssignableFrom(logFactoryClass);
1231:                            if (implements LogFactory) {
1232:                                logDiagnostic("[CUSTOM LOG FACTORY] "
1233:                                        + logFactoryClass.getName()
1234:                                        + " implements LogFactory but was loaded by an incompatible classloader.");
1235:                            } else {
1236:                                logDiagnostic("[CUSTOM LOG FACTORY] "
1237:                                        + logFactoryClass.getName()
1238:                                        + " does not implement LogFactory.");
1239:                            }
1240:                        }
1241:                    } catch (SecurityException e) {
1242:                        //
1243:                        // The application is running within a hostile security environment.
1244:                        // This will make it very hard to diagnose issues with JCL.
1245:                        // Consider running less securely whilst debugging this issue.
1246:                        //
1247:                        logDiagnostic("[CUSTOM LOG FACTORY] SecurityException thrown whilst trying to determine whether "
1248:                                + "the compatibility was caused by a classloader conflict: "
1249:                                + e.getMessage());
1250:                    } catch (LinkageError e) {
1251:                        //
1252:                        // This should be an unusual circumstance.
1253:                        // LinkageError's usually indicate that a dependent class has incompatibly changed.
1254:                        // Another possibility may be an exception thrown by an initializer.
1255:                        // Time for a clean rebuild?
1256:                        //
1257:                        logDiagnostic("[CUSTOM LOG FACTORY] LinkageError thrown whilst trying to determine whether "
1258:                                + "the compatibility was caused by a classloader conflict: "
1259:                                + e.getMessage());
1260:                    } catch (ClassNotFoundException e) {
1261:                        //
1262:                        // LogFactory cannot be loaded by the classloader which loaded the custom factory implementation.
1263:                        // The custom implementation is not viable until this is corrected.
1264:                        // Ensure that the JCL jar and the custom class are available from the same classloader.
1265:                        // Running with diagnostics on should give information about the classloaders used
1266:                        // to load the custom factory.
1267:                        //
1268:                        logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by classloader which loaded the "
1269:                                + "custom LogFactory implementation. Is the custom factory in the right classloader?");
1270:                    }
1271:                }
1272:                return implements LogFactory;
1273:            }
1274:
1275:            /**
1276:             * Applets may run in an environment where accessing resources of a loader is
1277:             * a secure operation, but where the commons-logging library has explicitly
1278:             * been granted permission for that operation. In this case, we need to 
1279:             * run the operation using an AccessController.
1280:             */
1281:            private static InputStream getResourceAsStream(
1282:                    final ClassLoader loader, final String name) {
1283:                return (InputStream) AccessController
1284:                        .doPrivileged(new PrivilegedAction() {
1285:                            public Object run() {
1286:                                if (loader != null) {
1287:                                    return loader.getResourceAsStream(name);
1288:                                } else {
1289:                                    return ClassLoader
1290:                                            .getSystemResourceAsStream(name);
1291:                                }
1292:                            }
1293:                        });
1294:            }
1295:
1296:            /**
1297:             * Given a filename, return an enumeration of URLs pointing to
1298:             * all the occurrences of that filename in the classpath.
1299:             * <p>
1300:             * This is just like ClassLoader.getResources except that the
1301:             * operation is done under an AccessController so that this method will
1302:             * succeed when this jarfile is privileged but the caller is not.
1303:             * This method must therefore remain private to avoid security issues.
1304:             * <p>
1305:             * If no instances are found, an Enumeration is returned whose
1306:             * hasMoreElements method returns false (ie an "empty" enumeration).
1307:             * If resources could not be listed for some reason, null is returned.
1308:             */
1309:            private static Enumeration getResources(final ClassLoader loader,
1310:                    final String name) {
1311:                PrivilegedAction action = new PrivilegedAction() {
1312:                    public Object run() {
1313:                        try {
1314:                            if (loader != null) {
1315:                                return loader.getResources(name);
1316:                            } else {
1317:                                return ClassLoader.getSystemResources(name);
1318:                            }
1319:                        } catch (IOException e) {
1320:                            if (isDiagnosticsEnabled()) {
1321:                                logDiagnostic("Exception while trying to find configuration file "
1322:                                        + name + ":" + e.getMessage());
1323:                            }
1324:                            return null;
1325:                        } catch (NoSuchMethodError e) {
1326:                            // we must be running on a 1.1 JVM which doesn't support
1327:                            // ClassLoader.getSystemResources; just return null in
1328:                            // this case.
1329:                            return null;
1330:                        }
1331:                    }
1332:                };
1333:                Object result = AccessController.doPrivileged(action);
1334:                return (Enumeration) result;
1335:            }
1336:
1337:            /**
1338:             * Given a URL that refers to a .properties file, load that file.
1339:             * This is done under an AccessController so that this method will
1340:             * succeed when this jarfile is privileged but the caller is not.
1341:             * This method must therefore remain private to avoid security issues.
1342:             * <p>
1343:             * Null is returned if the URL cannot be opened.
1344:             */
1345:            private static Properties getProperties(final URL url) {
1346:                PrivilegedAction action = new PrivilegedAction() {
1347:                    public Object run() {
1348:                        try {
1349:                            InputStream stream = url.openStream();
1350:                            if (stream != null) {
1351:                                Properties props = new Properties();
1352:                                props.load(stream);
1353:                                stream.close();
1354:                                return props;
1355:                            }
1356:                        } catch (IOException e) {
1357:                            if (isDiagnosticsEnabled()) {
1358:                                logDiagnostic("Unable to read URL " + url);
1359:                            }
1360:                        }
1361:
1362:                        return null;
1363:                    }
1364:                };
1365:                return (Properties) AccessController.doPrivileged(action);
1366:            }
1367:
1368:            /**
1369:             * Locate a user-provided configuration file.
1370:             * <p>
1371:             * The classpath of the specified classLoader (usually the context classloader)
1372:             * is searched for properties files of the specified name. If none is found,
1373:             * null is returned. If more than one is found, then the file with the greatest
1374:             * value for its PRIORITY property is returned. If multiple files have the
1375:             * same PRIORITY value then the first in the classpath is returned.
1376:             * <p> 
1377:             * This differs from the 1.0.x releases; those always use the first one found.
1378:             * However as the priority is a new field, this change is backwards compatible.
1379:             * <p>
1380:             * The purpose of the priority field is to allow a webserver administrator to
1381:             * override logging settings in all webapps by placing a commons-logging.properties
1382:             * file in a shared classpath location with a priority > 0; this overrides any
1383:             * commons-logging.properties files without priorities which are in the
1384:             * webapps. Webapps can also use explicit priorities to override a configuration
1385:             * file in the shared classpath if needed. 
1386:             */
1387:            private static final Properties getConfigurationFile(
1388:                    ClassLoader classLoader, String fileName) {
1389:
1390:                Properties props = null;
1391:                double priority = 0.0;
1392:                URL propsUrl = null;
1393:                try {
1394:                    Enumeration urls = getResources(classLoader, fileName);
1395:
1396:                    if (urls == null) {
1397:                        return null;
1398:                    }
1399:
1400:                    while (urls.hasMoreElements()) {
1401:                        URL url = (URL) urls.nextElement();
1402:
1403:                        Properties newProps = getProperties(url);
1404:                        if (newProps != null) {
1405:                            if (props == null) {
1406:                                propsUrl = url;
1407:                                props = newProps;
1408:                                String priorityStr = props
1409:                                        .getProperty(PRIORITY_KEY);
1410:                                priority = 0.0;
1411:                                if (priorityStr != null) {
1412:                                    priority = Double.parseDouble(priorityStr);
1413:                                }
1414:
1415:                                if (isDiagnosticsEnabled()) {
1416:                                    logDiagnostic("[LOOKUP] Properties file found at '"
1417:                                            + url
1418:                                            + "'"
1419:                                            + " with priority "
1420:                                            + priority);
1421:                                }
1422:                            } else {
1423:                                String newPriorityStr = newProps
1424:                                        .getProperty(PRIORITY_KEY);
1425:                                double newPriority = 0.0;
1426:                                if (newPriorityStr != null) {
1427:                                    newPriority = Double
1428:                                            .parseDouble(newPriorityStr);
1429:                                }
1430:
1431:                                if (newPriority > priority) {
1432:                                    if (isDiagnosticsEnabled()) {
1433:                                        logDiagnostic("[LOOKUP] Properties file at '"
1434:                                                + url
1435:                                                + "'"
1436:                                                + " with priority "
1437:                                                + newPriority
1438:                                                + " overrides file at '"
1439:                                                + propsUrl
1440:                                                + "'"
1441:                                                + " with priority " + priority);
1442:                                    }
1443:
1444:                                    propsUrl = url;
1445:                                    props = newProps;
1446:                                    priority = newPriority;
1447:                                } else {
1448:                                    if (isDiagnosticsEnabled()) {
1449:                                        logDiagnostic("[LOOKUP] Properties file at '"
1450:                                                + url
1451:                                                + "'"
1452:                                                + " with priority "
1453:                                                + newPriority
1454:                                                + " does not override file at '"
1455:                                                + propsUrl
1456:                                                + "'"
1457:                                                + " with priority " + priority);
1458:                                    }
1459:                                }
1460:                            }
1461:
1462:                        }
1463:                    }
1464:                } catch (SecurityException e) {
1465:                    if (isDiagnosticsEnabled()) {
1466:                        logDiagnostic("SecurityException thrown while trying to find/read config files.");
1467:                    }
1468:                }
1469:
1470:                if (isDiagnosticsEnabled()) {
1471:                    if (props == null) {
1472:                        logDiagnostic("[LOOKUP] No properties file of name '"
1473:                                + fileName + "' found.");
1474:                    } else {
1475:                        logDiagnostic("[LOOKUP] Properties file of name '"
1476:                                + fileName + "' found at '" + propsUrl + '"');
1477:                    }
1478:                }
1479:
1480:                return props;
1481:            }
1482:
1483:            /**
1484:             * Determines whether the user wants internal diagnostic output. If so,
1485:             * returns an appropriate writer object. Users can enable diagnostic
1486:             * output by setting the system property named {@link #DIAGNOSTICS_DEST_PROPERTY} to
1487:             * a filename, or the special values STDOUT or STDERR. 
1488:             */
1489:            private static void initDiagnostics() {
1490:                String dest;
1491:                try {
1492:                    dest = System.getProperty(DIAGNOSTICS_DEST_PROPERTY);
1493:                    if (dest == null) {
1494:                        return;
1495:                    }
1496:                } catch (SecurityException ex) {
1497:                    // We must be running in some very secure environment.
1498:                    // We just have to assume output is not wanted..
1499:                    return;
1500:                }
1501:
1502:                if (dest.equals("STDOUT")) {
1503:                    diagnosticsStream = System.out;
1504:                } else if (dest.equals("STDERR")) {
1505:                    diagnosticsStream = System.err;
1506:                } else {
1507:                    try {
1508:                        // open the file in append mode
1509:                        FileOutputStream fos = new FileOutputStream(dest, true);
1510:                        diagnosticsStream = new PrintStream(fos);
1511:                    } catch (IOException ex) {
1512:                        // We should report this to the user - but how?
1513:                        return;
1514:                    }
1515:                }
1516:
1517:                // In order to avoid confusion where multiple instances of JCL are
1518:                // being used via different classloaders within the same app, we
1519:                // ensure each logged message has a prefix of form
1520:                // [LogFactory from classloader OID]
1521:                //
1522:                // Note that this prefix should be kept consistent with that 
1523:                // in LogFactoryImpl. However here we don't need to output info
1524:                // about the actual *instance* of LogFactory, as all methods that
1525:                // output diagnostics from this class are static.
1526:                String classLoaderName;
1527:                try {
1528:                    ClassLoader classLoader = this ClassLoader;
1529:                    if (this ClassLoader == null) {
1530:                        classLoaderName = "BOOTLOADER";
1531:                    } else {
1532:                        classLoaderName = objectId(classLoader);
1533:                    }
1534:                } catch (SecurityException e) {
1535:                    classLoaderName = "UNKNOWN";
1536:                }
1537:                diagnosticPrefix = "[LogFactory from " + classLoaderName + "] ";
1538:            }
1539:
1540:            /**
1541:             * Indicates true if the user has enabled internal logging.
1542:             * <p>
1543:             * By the way, sorry for the incorrect grammar, but calling this method
1544:             * areDiagnosticsEnabled just isn't java beans style.
1545:             * 
1546:             * @return true if calls to logDiagnostic will have any effect.
1547:             * @since 1.1
1548:             */
1549:            protected static boolean isDiagnosticsEnabled() {
1550:                return diagnosticsStream != null;
1551:            }
1552:
1553:            /**
1554:             * Write the specified message to the internal logging destination.
1555:             * <p>
1556:             * Note that this method is private; concrete subclasses of this class
1557:             * should not call it because the diagnosticPrefix string this
1558:             * method puts in front of all its messages is LogFactory@....,
1559:             * while subclasses should put SomeSubClass@...
1560:             * <p>
1561:             * Subclasses should instead compute their own prefix, then call
1562:             * logRawDiagnostic. Note that calling isDiagnosticsEnabled is
1563:             * fine for subclasses.
1564:             * <p>
1565:             * Note that it is safe to call this method before initDiagnostics
1566:             * is called; any output will just be ignored (as isDiagnosticsEnabled
1567:             * will return false).
1568:             * 
1569:             * @param msg is the diagnostic message to be output.
1570:             */
1571:            private static final void logDiagnostic(String msg) {
1572:                if (diagnosticsStream != null) {
1573:                    diagnosticsStream.print(diagnosticPrefix);
1574:                    diagnosticsStream.println(msg);
1575:                    diagnosticsStream.flush();
1576:                }
1577:            }
1578:
1579:            /**
1580:             * Write the specified message to the internal logging destination.
1581:             * 
1582:             * @param msg is the diagnostic message to be output.
1583:             * @since 1.1
1584:             */
1585:            protected static final void logRawDiagnostic(String msg) {
1586:                if (diagnosticsStream != null) {
1587:                    diagnosticsStream.println(msg);
1588:                    diagnosticsStream.flush();
1589:                }
1590:            }
1591:
1592:            /**
1593:             * Generate useful diagnostics regarding the classloader tree for
1594:             * the specified class.
1595:             * <p>
1596:             * As an example, if the specified class was loaded via a webapp's
1597:             * classloader, then you may get the following output:
1598:             * <pre>
1599:             * Class com.acme.Foo was loaded via classloader 11111
1600:             * ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT 
1601:             * </pre>
1602:             * <p>
1603:             * This method returns immediately if isDiagnosticsEnabled()
1604:             * returns false.
1605:             * 
1606:             * @param clazz is the class whose classloader + tree are to be
1607:             * output.
1608:             */
1609:            private static void logClassLoaderEnvironment(Class clazz) {
1610:                if (!isDiagnosticsEnabled()) {
1611:                    return;
1612:                }
1613:
1614:                try {
1615:                    logDiagnostic("[ENV] Extension directories (java.ext.dir): "
1616:                            + System.getProperty("java.ext.dir"));
1617:                    logDiagnostic("[ENV] Application classpath (java.class.path): "
1618:                            + System.getProperty("java.class.path"));
1619:                } catch (SecurityException ex) {
1620:                    logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths.");
1621:                }
1622:
1623:                String className = clazz.getName();
1624:                ClassLoader classLoader;
1625:
1626:                try {
1627:                    classLoader = getClassLoader(clazz);
1628:                } catch (SecurityException ex) {
1629:                    // not much useful diagnostics we can print here!
1630:                    logDiagnostic("[ENV] Security forbids determining the classloader for "
1631:                            + className);
1632:                    return;
1633:                }
1634:
1635:                logDiagnostic("[ENV] Class " + className
1636:                        + " was loaded via classloader "
1637:                        + objectId(classLoader));
1638:                logHierarchy("[ENV] Ancestry of classloader which loaded "
1639:                        + className + " is ", classLoader);
1640:            }
1641:
1642:            /**
1643:             * Logs diagnostic messages about the given classloader
1644:             * and it's hierarchy. The prefix is prepended to the message
1645:             * and is intended to make it easier to understand the logs.
1646:             * @param prefix 
1647:             * @param classLoader
1648:             */
1649:            private static void logHierarchy(String prefix,
1650:                    ClassLoader classLoader) {
1651:                if (!isDiagnosticsEnabled()) {
1652:                    return;
1653:                }
1654:                ClassLoader systemClassLoader;
1655:                if (classLoader != null) {
1656:                    final String classLoaderString = classLoader.toString();
1657:                    logDiagnostic(prefix + objectId(classLoader) + " == '"
1658:                            + classLoaderString + "'");
1659:                }
1660:
1661:                try {
1662:                    systemClassLoader = ClassLoader.getSystemClassLoader();
1663:                } catch (SecurityException ex) {
1664:                    logDiagnostic(prefix
1665:                            + "Security forbids determining the system classloader.");
1666:                    return;
1667:                }
1668:                if (classLoader != null) {
1669:                    StringBuffer buf = new StringBuffer(prefix
1670:                            + "ClassLoader tree:");
1671:                    for (;;) {
1672:                        buf.append(objectId(classLoader));
1673:                        if (classLoader == systemClassLoader) {
1674:                            buf.append(" (SYSTEM) ");
1675:                        }
1676:
1677:                        try {
1678:                            classLoader = classLoader.getParent();
1679:                        } catch (SecurityException ex) {
1680:                            buf.append(" --> SECRET");
1681:                            break;
1682:                        }
1683:
1684:                        buf.append(" --> ");
1685:                        if (classLoader == null) {
1686:                            buf.append("BOOT");
1687:                            break;
1688:                        }
1689:                    }
1690:                    logDiagnostic(buf.toString());
1691:                }
1692:            }
1693:
1694:            /**
1695:             * Returns a string that uniquely identifies the specified object, including
1696:             * its class.
1697:             * <p>
1698:             * The returned string is of form "classname@hashcode", ie is the same as
1699:             * the return value of the Object.toString() method, but works even when
1700:             * the specified object's class has overidden the toString method.
1701:             * 
1702:             * @param o may be null.
1703:             * @return a string of form classname@hashcode, or "null" if param o is null.
1704:             * @since 1.1
1705:             */
1706:            public static String objectId(Object o) {
1707:                if (o == null) {
1708:                    return "null";
1709:                } else {
1710:                    return o.getClass().getName() + "@"
1711:                            + System.identityHashCode(o);
1712:                }
1713:            }
1714:
1715:            // ----------------------------------------------------------------------
1716:            // Static initialiser block to perform initialisation at class load time.
1717:            //
1718:            // We can't do this in the class constructor, as there are many 
1719:            // static methods on this class that can be called before any
1720:            // LogFactory instances are created, and they depend upon this
1721:            // stuff having been set up.
1722:            //
1723:            // Note that this block must come after any variable declarations used
1724:            // by any methods called from this block, as we want any static initialiser
1725:            // associated with the variable to run first. If static initialisers for
1726:            // variables run after this code, then (a) their value might be needed
1727:            // by methods called from here, and (b) they might *override* any value
1728:            // computed here!
1729:            //
1730:            // So the wisest thing to do is just to place this code at the very end
1731:            // of the class file.
1732:            // ----------------------------------------------------------------------
1733:
1734:            static {
1735:                // note: it's safe to call methods before initDiagnostics.
1736:                this ClassLoader = getClassLoader(LogFactory.class);
1737:                initDiagnostics();
1738:                logClassLoaderEnvironment(LogFactory.class);
1739:                factories = createFactoryStore();
1740:                if (isDiagnosticsEnabled()) {
1741:                    logDiagnostic("BOOTSTRAP COMPLETED");
1742:                }
1743:            }
1744:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.