factoryfinder.java

来自「JAVA的一些源码 JAVA2 STANDARD EDITION DEVELO」· Java 代码 · 共 358 行

JAVA
358
字号
/* * The Apache Software License, Version 1.1 * * * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights  * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer.  * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. The end-user documentation included with the redistribution, *    if any, must include the following acknowledgment:   *       "This product includes software developed by the *        Apache Software Foundation (http://www.apache.org/)." *    Alternately, this acknowledgment may appear in the software itself, *    if and wherever such third-party acknowledgments normally appear. * * 4. The name "Apache Software Foundation" must not be used to endorse or *    promote products derived from this software without prior written *    permission. For written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", *    nor may "Apache" appear in their name, without prior written *    permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999-2001, Sun Microsystems, * Inc., http://www.sun.com.  For more information on the Apache Software * Foundation, please see <http://www.apache.org/>. */package com.sun.org.apache.xml.internal.dtm;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.Properties;/** * This class is based on the FactoryFinder classes in the JAXP subpackages * in the xml-commons project (xml-apis.jar) * * This copy of FactoryFinder is for the DTMManager.  It caches the class * name after it is found the first time, if the System.property is not set. * If the System.property is set, then it is always used. *  * It does not use context class loaders, but we will probably need to add * this support in the future.  Question: If we use context class loaders, can * we still cache the class (do we need to also cache the class loader for * comparison purposes)? *  * @author Edwin Goei, Ilene Seelemann */class FactoryFinder {    /** Controls debugging output to stderr */    private static boolean debug;       /**    * Avoid reading all the files when the findFactory    * method is called the second time (cache the result of    * finding the default impl).    */   private static String foundFactory = null;       // Define system property "jaxp.debug" to get output    static {        try {            String val =                SecuritySupport.getInstance().getSystemProperty("jaxp.debug");            // Allow simply setting the prop to turn on debug            debug = val != null && (! "false".equals(val));        } catch (SecurityException se) {            debug = false;        }    }    /**     * Main entry point.  Finds and creates a new instance of a concrete     * factory implementation in the specified order as stated in the JAXP     * spec.  This code attempts to find a factory implementation in     * serveral locations.  If one fails, the next one is tried.  To be     * more robust, this occurs even if a SecurityException is thrown, but     * perhaps it may be better to propogate the SecurityException instead,     * so SecurityException-s are not masked.     *     * @return A new instance of the concrete factory class, never null     *     * @param factoryId     *        Name of the factory to find, same as a property name     *     * @param fallbackClassName     *        Implementation class name, if nothing else is found.  Use     *        null to mean not to use a fallback.     *     * @throws FactoryFinder.ConfigurationError     *         If a factory instance cannot be returned     *     * Package private so this code can be shared.     */    static Object find(String factoryId, String fallbackClassName)        throws ConfigurationError    {        SecuritySupport ss = SecuritySupport.getInstance();        ClassLoader cl = FactoryFinder.class.getClassLoader();        dPrint("find factoryId=" + factoryId);        // Use the system property first        try {            String systemProp = ss.getSystemProperty(factoryId);            if (systemProp != null) {                dPrint("found system property, value=" + systemProp);                                return newInstance(systemProp, cl, true);            }                    } catch (SecurityException se) {            // Ignore and continue w/ next location        }           synchronized (FactoryFinder.class) {                        // This block will only run once, and then foundFactory will            // be set and immutable.  Currently there is no support in this            // class for context class loaders.  If the contents of the             // xalan.properties file changes, or the class loader changes,            // this will *not* affect the cached class.               if (foundFactory == null) {                          // Try to read from $java.home/lib/xalan.properties               Properties xalanProperties = null;                try {                   String javah = ss.getSystemProperty("java.home");                   String configFile = javah + File.separator +                        "lib" + File.separator + "xalan.properties";                   File f = new File(configFile);                   FileInputStream fis = ss.getFileInputStream(f);                   xalanProperties = new Properties();                   xalanProperties.load(fis);                   fis.close();                                  } catch (Exception x) {                // assert(x instanceof FileNotFoundException                //        || x instanceof SecurityException)                // In both cases, ignore and continue w/ next location               }                              if (xalanProperties != null) {                               foundFactory = xalanProperties.getProperty(factoryId);                   if (foundFactory != null) {                       dPrint("found in xalan.properties, value=" + foundFactory);                   }                } else {                        // Try Jar Service Provider Mechanism                    // (foundFactory gets set in findJarServiceProvider method)                    findJarServiceProvider(factoryId);                            if (foundFactory == null) {                        if (fallbackClassName == null) {                            throw new ConfigurationError(                            "Provider for " + factoryId + " cannot be found", null);                        }                        dPrint("using fallback, value=" + fallbackClassName);                        foundFactory = fallbackClassName;                            }               }               }                       }                    return newInstance(foundFactory, cl, true);    }    private static void dPrint(String msg) {        if (debug) {            System.err.println("JAXP: " + msg);        }    }    /**     * Create an instance of a class using the specified ClassLoader and     * optionally fall back to the current ClassLoader if not found.     *     * @param className Name of the concrete class corresponding to the     * service provider     *     * @param cl ClassLoader to use to load the class, null means to use     * the bootstrap ClassLoader     *     * @param doFallback true if the current ClassLoader should be tried as     * a fallback if the class is not found using cl     */    private static Object newInstance(String className, ClassLoader cl,                                      boolean doFallback)        throws ConfigurationError    {        // assert(className != null);        try {            Class providerClass;            if (cl == null) {                // XXX Use the bootstrap ClassLoader.  There is no way to                // load a class using the bootstrap ClassLoader that works                // in both JDK 1.1 and Java 2.  However, this should still                // work b/c the following should be true:                //                // (cl == null) iff current ClassLoader == null                //                // Thus Class.forName(String) will use the current                // ClassLoader which will be the bootstrap ClassLoader.                providerClass = Class.forName(className);            } else {                try {                    providerClass = cl.loadClass(className);                } catch (ClassNotFoundException x) {                    if (doFallback) {                        // Fall back to current classloader                        cl = FactoryFinder.class.getClassLoader();                        providerClass = cl.loadClass(className);                    } else {                        throw x;                    }                }            }            Object instance = providerClass.newInstance();            dPrint("created new instance of " + providerClass +                   " using ClassLoader: " + cl);            return instance;        } catch (ClassNotFoundException x) {            throw new ConfigurationError(                "Provider " + className + " not found", x);        } catch (Exception x) {            throw new ConfigurationError(                "Provider " + className + " could not be instantiated: " + x,                x);        }    }    /*     * Try to find provider using Jar Service Provider Mechanism     *     * @return instance of provider class if found or null     */    private static String findJarServiceProvider(String factoryId)        throws ConfigurationError    {        SecuritySupport ss = SecuritySupport.getInstance();        String serviceId = "META-INF/services/" + factoryId;        InputStream is = null;        // No support yet for context class loader        ClassLoader cl = FactoryFinder.class.getClassLoader();        is = ss.getResourceAsStream(cl, serviceId);        if (is == null) {            // No provider found            return null;        }        dPrint("found jar resource=" + serviceId +               " using ClassLoader: " + cl);        // Read the service provider name in UTF-8 as specified in        // the jar spec.  Unfortunately this fails in Microsoft        // VJ++, which does not implement the UTF-8        // encoding. Theoretically, we should simply let it fail in        // that case, since the JVM is obviously broken if it        // doesn't support such a basic standard.  But since there        // are still some users attempting to use VJ++ for        // development, we have dropped in a fallback which makes a        // second attempt using the platform's default encoding. In        // VJ++ this is apparently ASCII, which is a subset of        // UTF-8... and since the strings we'll be reading here are        // also primarily limited to the 7-bit ASCII range (at        // least, in English versions), this should work well        // enough to keep us on the air until we're ready to        // officially decommit from VJ++. [Edited comment from        // jkesselm]        BufferedReader rd;        try {            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));        } catch (java.io.UnsupportedEncodingException e) {            rd = new BufferedReader(new InputStreamReader(is));        }                String factoryClassName = null;        try {            // XXX Does not handle all possible input as specified by the            // Jar Service Provider specification            factoryClassName = rd.readLine();            rd.close();        } catch (IOException x) {            // No provider found            return null;        }        if (factoryClassName != null &&            ! "".equals(factoryClassName)) {            dPrint("found in resource, value="                   + factoryClassName);            // Note: here we do not want to fall back to the current            // ClassLoader because we want to avoid the case where the            // resource file was found using one ClassLoader and the            // provider class was instantiated using a different one.            return factoryClassName;        }        // No provider found        return null;    }    static class ConfigurationError extends Error {        private Exception exception;        /**         * Construct a new instance with the specified detail string and         * exception.         */        ConfigurationError(String msg, Exception x) {            super(msg);            this.exception = x;        }        Exception getException() {            return exception;        }    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?