FactoryFinder.java revision d21d78fd49a2d798218e8c8aefbddb26a0e71bbb
1320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/*
2320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one or more
3320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * contributor license agreements.  See the NOTICE file distributed with
4320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * this work for additional information regarding copyright ownership.
5320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * The ASF licenses this file to You under the Apache License, Version 2.0
6320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * (the "License"); you may not use this file except in compliance with
7320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the License.  You may obtain a copy of the License at
8320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
9320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
10320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
11320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Unless required by applicable law or agreed to in writing, software
12320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
13320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * See the License for the specific language governing permissions and
15320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * limitations under the License.
16320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */
17320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
18320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson// $Id: FactoryFinder.java 670432 2008-06-23 02:02:08Z mrglavas $
19320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
20320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonpackage javax.xml.datatype;
21320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
22320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.BufferedReader;
23320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.File;
24320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.IOException;
25320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStream;
26320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStreamReader;
27320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.net.URL;
28320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Properties;
29320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
30320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/**
31320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Implement pluggabile Datatypes.</p>
32320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
33320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>This class is duplicated for each JAXP subpackage so keep it in
34320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * sync.  It is package private for secure class loading.</p>
35320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
36320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
37320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @version $Revision: 670432 $, $Date: 2008-06-22 19:02:08 -0700 (Sun, 22 Jun 2008) $
38320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @since 1.5
39320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */
40320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonfinal class FactoryFinder {
41d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
42d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
43d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Name of class to display in output messages.</p>
44d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
45d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static final String CLASS_NAME = "javax.xml.datatype.FactoryFinder";
46d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
47320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
48320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Debug flag to trace loading process.</p>
49320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
50320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static boolean debug = false;
51320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
52320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
53320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Cache properties for performance.</p>
54320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
55d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static Properties cacheProps = new Properties();
56d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
57d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
58d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>First time requires initialization overhead.</p>
59d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
60d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static boolean firstTime = true;
61320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
62320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
63320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Default columns per line.
64320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
65320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static final int DEFAULT_LINE_LENGTH = 80;
66d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
67d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
68d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Check to see if debugging enabled by property.</p>
69d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     *
70d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Use try/catch block to support applets, which throws
71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * SecurityException out of this code.</p>
72d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     *
73d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
74320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static {
75320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
76320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String val = SecuritySupport.getSystemProperty("jaxp.debug");
77320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // Allow simply setting the prop to turn on debug
78320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            debug = val != null && (! "false".equals(val));
79320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (Exception x) {
80320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            debug = false;
81320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
82320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
83320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
84320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private FactoryFinder() {}
85320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
86d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
87d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Output debugging messages.</p>
88d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     *
89d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * @param msg <code>String</code> to print to <code>stderr</code>.
90d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
91320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static void debugPrintln(String msg) {
92320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) {
93320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            System.err.println(
94d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                CLASS_NAME
95d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                + ":"
96d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                + msg);
97320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
98320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
99320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
100320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
101320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Find the appropriate <code>ClassLoader</code> to use.</p>
102320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
103320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>The context ClassLoader is prefered.</p>
104320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
105320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return <code>ClassLoader</code> to use.
106320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
107320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified.
108320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
109320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static ClassLoader findClassLoader()
110320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throws ConfigurationError {
111320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ClassLoader classLoader;
112320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
113320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // Figure out which ClassLoader to use for loading the provider
114320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // class.  If there is a Context ClassLoader then use it.
115320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
116320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        classLoader = SecuritySupport.getContextClassLoader();
117320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
118320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) debugPrintln(
119320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            "Using context class loader: "
120320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            + classLoader);
121320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
122320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (classLoader == null) {
123320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // if we have no Context ClassLoader
124320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // so use the current ClassLoader
125320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            classLoader = FactoryFinder.class.getClassLoader();
126320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) debugPrintln(
127320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Using the class loader of FactoryFinder: "
128320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + classLoader);
129320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
130320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
131320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return classLoader;
132320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
133320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
134320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
135320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Create an instance of a class using the specified ClassLoader.</p>
136320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
137320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param className Name of class to create.
138320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param classLoader ClassLoader to use to create named class.
139320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
140320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return New instance of specified class created using the specified ClassLoader.
141320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
142320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws ConfigurationError If class could not be created.
143320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
144320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static Object newInstance(
145d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        String className,
146320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ClassLoader classLoader)
147320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throws ConfigurationError {
148d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
149320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
150320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            Class spiClass;
151320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (classLoader == null) {
152320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                spiClass = Class.forName(className);
153320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            } else {
154320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                spiClass = classLoader.loadClass(className);
155320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
156320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
157320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) {
158d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                debugPrintln("Loaded " + className + " from " + which(spiClass));
159320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
160320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
161320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return spiClass.newInstance();
162320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (ClassNotFoundException x) {
163320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw new ConfigurationError(
164320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Provider " + className + " not found", x);
165320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (Exception x) {
166320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw new ConfigurationError(
167320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Provider " + className + " could not be instantiated: " + x,
168320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                x);
169320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
170320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
171320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
172320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
173320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Finds the implementation Class object in the specified order.  Main
174320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * entry point.
175320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Package private so this code can be shared.
176320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
177320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param factoryId Name of the factory to find, same as a property name
178320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param fallbackClassName Implementation class name, if nothing else is found.  Use null to mean no fallback.
179320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
180320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Class Object of factory, never null
181320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
182320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws ConfigurationError If Class cannot be found.
183320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
184320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static Object find(String factoryId, String fallbackClassName)
185320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throws ConfigurationError {
186d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
187320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ClassLoader classLoader = findClassLoader();
188320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
189320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // Use the system property first
190320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
191320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String systemProp = SecuritySupport.getSystemProperty(factoryId);
192320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (systemProp != null && systemProp.length() > 0) {
193320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                if (debug) debugPrintln("found " + systemProp + " in the system property " + factoryId);
194320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                return newInstance(systemProp, classLoader);
195320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
196320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (SecurityException se) {
197d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            ; // NOP, explicitly ignore SecurityException
198320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
199320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
200320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // try to read from $java.home/lib/jaxp.properties
201320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
202320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String javah = SecuritySupport.getSystemProperty("java.home");
203320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
204d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            String factoryClassName = null;
205d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            if (firstTime) {
206d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                synchronized (cacheProps) {
207d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                    if (firstTime) {
208d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        File f = new File(configFile);
209d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        firstTime = false;
210d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        if (SecuritySupport.doesFileExist(f)) {
211d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                            if (debug) debugPrintln("Read properties file " + f);
212d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                            cacheProps.load(SecuritySupport.getFileInputStream(f));
213d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        }
214d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                    }
215d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                }
216d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            }
217d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            factoryClassName = cacheProps.getProperty(factoryId);
218320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
219d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
220d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            if (factoryClassName != null) {
221d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                return newInstance(factoryClassName, classLoader);
222d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            }
223320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (Exception ex) {
224320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) {
225d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                ex.printStackTrace();
226320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
227320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
228320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
229320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // Try Jar Service Provider Mechanism
230320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Object provider = findJarServiceProvider(factoryId);
231320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (provider != null) {
232320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return provider;
233320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
234320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
235320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (fallbackClassName == null) {
236320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw new ConfigurationError(
237320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Provider for " + factoryId + " cannot be found", null);
238320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
239320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
240320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) debugPrintln("loaded from fallback value: " + fallbackClassName);
241320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return newInstance(fallbackClassName, classLoader);
242320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
243320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
244320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /*
245320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Try to find provider using Jar Service Provider Mechanism
246320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
247320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return instance of provider class if found or null
248320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
249320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static Object findJarServiceProvider(String factoryId)
250320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throws ConfigurationError
251320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    {
252320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
253320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        String serviceId = "META-INF/services/" + factoryId;
254320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        InputStream is = null;
255320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
256320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // First try the Context ClassLoader
257320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ClassLoader cl = SecuritySupport.getContextClassLoader();
258320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (cl != null) {
259320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            is = SecuritySupport.getResourceAsStream(cl, serviceId);
260320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
261320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // If no provider found then try the current ClassLoader
262320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (is == null) {
263320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                cl = FactoryFinder.class.getClassLoader();
264320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                is = SecuritySupport.getResourceAsStream(cl, serviceId);
265320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
266320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } else {
267320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // No Context ClassLoader, try the current
268320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // ClassLoader
269320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            cl = FactoryFinder.class.getClassLoader();
270320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            is = SecuritySupport.getResourceAsStream(cl, serviceId);
271320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
272320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
273320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (is == null) {
274320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // No provider found
275320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return null;
276320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
277320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
278320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) debugPrintln("found jar resource=" + serviceId +
279320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson               " using ClassLoader: " + cl);
280320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
281320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BufferedReader rd;
282320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
283320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
284320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (java.io.UnsupportedEncodingException e) {
285320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
286320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
287320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
288320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        String factoryClassName = null;
289320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
290320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // XXX Does not handle all possible input as specified by the
291320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // Jar Service Provider specification
292320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            factoryClassName = rd.readLine();
293320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
294320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (IOException x) {
295320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // No provider found
296320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return null;
297320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
298320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        finally {
299320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            try {
300320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                // try to close the reader.
301320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                rd.close();
302320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
303320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // Ignore the exception.
304320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            catch (IOException exc) {}
305320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
306320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
307320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (factoryClassName != null &&
308320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            ! "".equals(factoryClassName)) {
309320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) debugPrintln("found in resource, value="
310320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                   + factoryClassName);
311320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
312320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return newInstance(factoryClassName, cl);
313320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
314320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
315320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // No provider found
316320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return null;
317320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
318320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
319d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
320d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Configuration Error.</p>
321d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
322320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static class ConfigurationError extends Error {
323320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
324320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        private static final long serialVersionUID = -3644413026244211347L;
325d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes
326d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        /**
327d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         * <p>Exception that caused the error.</p>
328d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         */
329320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        private Exception exception;
330320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
331320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        /**
332320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * <p>Construct a new instance with the specified detail string and
333320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * exception.</p>
334320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         *
335320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * @param msg Detail message for this error.
336320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * @param x Exception that caused the error.
337320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         */
338320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ConfigurationError(String msg, Exception x) {
339320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            super(msg);
340320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            this.exception = x;
341320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
342320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
343d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        /**
344d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         * <p>Get the Exception that caused the error.</p>
345d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         *
346d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         * @return Exception that caused the error.
347d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         */
348320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Exception getException() {
349320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return exception;
350320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
351320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
352320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
353320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
354320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
355320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
356320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Returns the location where the given Class is loaded from.
357320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
358320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param clazz Class to find load location.
359320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
360320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Location where class would be loaded from.
361320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
362320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static String which(Class clazz) {
363320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
364320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String classnameAsResource = clazz.getName().replace('.', '/') + ".class";
365320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
366320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            ClassLoader loader = clazz.getClassLoader();
367320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
368320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            URL it;
369320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
370320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (loader != null) {
371d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                it = loader.getResource(classnameAsResource);
372320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            } else {
373d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                it = ClassLoader.getSystemResource(classnameAsResource);
374320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
375320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
376320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (it != null) {
377d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                return it.toString();
378320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
379320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
380320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // The VM ran out of memory or there was some other serious problem. Re-throw.
381320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (VirtualMachineError vme) {
382320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw vme;
383320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
384320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // ThreadDeath should always be re-thrown
385320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (ThreadDeath td) {
386320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw td;
387320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
388320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (Throwable t) {
389320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // work defensively.
390320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) {
391d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                t.printStackTrace();
392320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
393320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
394320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return "unknown location";
395320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
396320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson}
397