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;
24670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilsonimport java.io.FileInputStream;
25320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.IOException;
26320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStream;
27320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.io.InputStreamReader;
28320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.net.URL;
29320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Properties;
30a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilsonimport libcore.io.IoUtils;
31320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
32320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/**
33670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson * <p>Implement pluggable data types.</p>
34f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
35320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>This class is duplicated for each JAXP subpackage so keep it in
36320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * sync.  It is package private for secure class loading.</p>
37320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
38320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
39320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @version $Revision: 670432 $, $Date: 2008-06-22 19:02:08 -0700 (Sun, 22 Jun 2008) $
40320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @since 1.5
41320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */
42320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonfinal class FactoryFinder {
43f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
44670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    /** <p>Name of class to display in output messages.</p> */
45d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static final String CLASS_NAME = "javax.xml.datatype.FactoryFinder";
46f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
47670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    /** <p>Debug flag to trace loading process.</p> */
48320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static boolean debug = false;
49f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
50670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    /** <p>Cache properties for performance.</p> */
51d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static Properties cacheProps = new Properties();
52f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
53670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    /** <p>First time requires initialization overhead.</p> */
54d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    private static boolean firstTime = true;
55f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
56670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    /** Default columns per line. */
57320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static final int DEFAULT_LINE_LENGTH = 80;
58f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
59d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
60d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Check to see if debugging enabled by property.</p>
61f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
62d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Use try/catch block to support applets, which throws
63320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * SecurityException out of this code.</p>
64d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
65320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static {
66670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        String val = System.getProperty("jaxp.debug");
67670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        // Allow simply setting the prop to turn on debug
68670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        debug = val != null && (! "false".equals(val));
69320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
70f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private FactoryFinder() {}
72320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
73d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
74d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Output debugging messages.</p>
75f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
76d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * @param msg <code>String</code> to print to <code>stderr</code>.
77d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
78320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static void debugPrintln(String msg) {
79320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) {
80320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            System.err.println(
81d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                CLASS_NAME
82d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                + ":"
83d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                + msg);
84320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
85320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
86320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
87320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
88320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Find the appropriate <code>ClassLoader</code> to use.</p>
89f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
90670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson     * <p>The context ClassLoader is preferred.</p>
91f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
92320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return <code>ClassLoader</code> to use.
93f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
94f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @throws ConfigurationError If a valid <code>ClassLoader</code> cannot be identified.
95320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
96670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    private static ClassLoader findClassLoader() throws ConfigurationError {
97320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // Figure out which ClassLoader to use for loading the provider
98320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // class.  If there is a Context ClassLoader then use it.
99320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
100670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
101320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
102320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) debugPrintln(
103320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            "Using context class loader: "
104320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            + classLoader);
105320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
106320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (classLoader == null) {
107320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // if we have no Context ClassLoader
108320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // so use the current ClassLoader
109320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            classLoader = FactoryFinder.class.getClassLoader();
110320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) debugPrintln(
111320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Using the class loader of FactoryFinder: "
112f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                + classLoader);
113320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
114f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
115320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return classLoader;
116320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
117320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
118320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
119320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Create an instance of a class using the specified ClassLoader.</p>
120f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
121320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param className Name of class to create.
122320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param classLoader ClassLoader to use to create named class.
123f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
124320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return New instance of specified class created using the specified ClassLoader.
125f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
126320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws ConfigurationError If class could not be created.
127320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
128320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static Object newInstance(
129d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        String className,
130320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ClassLoader classLoader)
131320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throws ConfigurationError {
132f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
133320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
134320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            Class spiClass;
135320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (classLoader == null) {
136320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                spiClass = Class.forName(className);
137320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            } else {
138320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                spiClass = classLoader.loadClass(className);
139320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
140f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
141320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) {
142d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                debugPrintln("Loaded " + className + " from " + which(spiClass));
143320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
144f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
145320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return spiClass.newInstance();
146320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (ClassNotFoundException x) {
147320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw new ConfigurationError(
148320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Provider " + className + " not found", x);
149320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (Exception x) {
150320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw new ConfigurationError(
151670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson                "Provider " + className + " could not be instantiated: " + x, x);
152320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
153320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
154320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
155320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
156320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Finds the implementation Class object in the specified order.  Main
157320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * entry point.
158320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Package private so this code can be shared.
159320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
160320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param factoryId Name of the factory to find, same as a property name
161320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param fallbackClassName Implementation class name, if nothing else is found.  Use null to mean no fallback.
162320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
163320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Class Object of factory, never null
164f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
165320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws ConfigurationError If Class cannot be found.
166320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
167670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    static Object find(String factoryId, String fallbackClassName) throws ConfigurationError {
168f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
169320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ClassLoader classLoader = findClassLoader();
170320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
171320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // Use the system property first
172670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        String systemProp = System.getProperty(factoryId);
173670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        if (systemProp != null && systemProp.length() > 0) {
174670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson            if (debug) debugPrintln("found " + systemProp + " in the system property " + factoryId);
175670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson            return newInstance(systemProp, classLoader);
176320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
177320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
178320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // try to read from $java.home/lib/jaxp.properties
179320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
180670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson            String javah = System.getProperty("java.home");
181320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties";
182d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            String factoryClassName = null;
183d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            if (firstTime) {
184d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                synchronized (cacheProps) {
185d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                    if (firstTime) {
186d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        File f = new File(configFile);
187d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        firstTime = false;
188670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson                        if (f.exists()) {
189d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                            if (debug) debugPrintln("Read properties file " + f);
190670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson                            cacheProps.load(new FileInputStream(f));
191d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                        }
192d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                    }
193d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                }
194d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            }
195d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            factoryClassName = cacheProps.getProperty(factoryId);
196f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            if (debug) debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
197f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
198d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            if (factoryClassName != null) {
199d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                return newInstance(factoryClassName, classLoader);
200d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes            }
201320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (Exception ex) {
202320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) {
203d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                ex.printStackTrace();
204f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            }
205320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
206f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
207320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // Try Jar Service Provider Mechanism
208320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Object provider = findJarServiceProvider(factoryId);
209320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (provider != null) {
210320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return provider;
211320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
212320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
213320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (fallbackClassName == null) {
214320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw new ConfigurationError(
215320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "Provider for " + factoryId + " cannot be found", null);
216320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
217320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
218320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (debug) debugPrintln("loaded from fallback value: " + fallbackClassName);
219320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return newInstance(fallbackClassName, classLoader);
220320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
221320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
222320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /*
223320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Try to find provider using Jar Service Provider Mechanism
224320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
225320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return instance of provider class if found or null
226320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
227670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson    private static Object findJarServiceProvider(String factoryId) throws ConfigurationError {
228320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        String serviceId = "META-INF/services/" + factoryId;
229320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        InputStream is = null;
230320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
231320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // First try the Context ClassLoader
232670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        ClassLoader cl = Thread.currentThread().getContextClassLoader();
233320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (cl != null) {
234670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson            is = cl.getResourceAsStream(serviceId);
235670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        }
236320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
237670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        if (is == null) {
238320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            cl = FactoryFinder.class.getClassLoader();
239670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson            is = cl.getResourceAsStream(serviceId);
240320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
241320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
242320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (is == null) {
243320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // No provider found
244320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return null;
245320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
246320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
247670c354edf01dcda0d9c4363a0996923bb30169bJesse Wilson        if (debug) debugPrintln("found jar resource=" + serviceId + " using ClassLoader: " + cl);
248320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
249320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BufferedReader rd;
250320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
251320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"), DEFAULT_LINE_LENGTH);
252320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        } catch (java.io.UnsupportedEncodingException e) {
253320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            rd = new BufferedReader(new InputStreamReader(is), DEFAULT_LINE_LENGTH);
254320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
255f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
256320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        String factoryClassName = null;
257320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
258320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // XXX Does not handle all possible input as specified by the
259320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // Jar Service Provider specification
260320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            factoryClassName = rd.readLine();
261a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson        } catch (IOException x) {
262320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // No provider found
263320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return null;
264a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson        } finally {
265a7a70410e26802f3ab480b08a1ab499338cb6f7eJesse Wilson            IoUtils.closeQuietly(rd);
266320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
267320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
268320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (factoryClassName != null &&
269320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            ! "".equals(factoryClassName)) {
270320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) debugPrintln("found in resource, value="
271320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                   + factoryClassName);
272320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
273320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return newInstance(factoryClassName, cl);
274320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
275320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
276320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // No provider found
277320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return null;
278320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
279f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
280d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes    /**
281d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     * <p>Configuration Error.</p>
282d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes     */
283320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    static class ConfigurationError extends Error {
284f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
285320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        private static final long serialVersionUID = -3644413026244211347L;
286f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
287d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        /**
288d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         * <p>Exception that caused the error.</p>
289d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         */
290320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        private Exception exception;
291320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
292320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        /**
293320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * <p>Construct a new instance with the specified detail string and
294320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * exception.</p>
295f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
296320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * @param msg Detail message for this error.
297320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         * @param x Exception that caused the error.
298320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson         */
299320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        ConfigurationError(String msg, Exception x) {
300320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            super(msg);
301320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            this.exception = x;
302320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
303320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
304d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes        /**
305d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         * <p>Get the Exception that caused the error.</p>
306f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         *
307d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         * @return Exception that caused the error.
308d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes         */
309320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Exception getException() {
310320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return exception;
311320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
312320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
313320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
314320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
315320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Returns the location where the given Class is loaded from.
316320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
317320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static String which(Class clazz) {
318320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        try {
319320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            String classnameAsResource = clazz.getName().replace('.', '/') + ".class";
320f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
321320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            ClassLoader loader = clazz.getClassLoader();
322f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
323320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            URL it;
324f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
325320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (loader != null) {
326d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                it = loader.getResource(classnameAsResource);
327320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            } else {
328d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                it = ClassLoader.getSystemResource(classnameAsResource);
329f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            }
330f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
331320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (it != null) {
332d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                return it.toString();
333f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            }
334320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
335320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // The VM ran out of memory or there was some other serious problem. Re-throw.
336320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (VirtualMachineError vme) {
337320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw vme;
338320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
339320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // ThreadDeath should always be re-thrown
340320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (ThreadDeath td) {
341320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            throw td;
342320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
343320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        catch (Throwable t) {
344320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            // work defensively.
345320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (debug) {
346d21d78fd49a2d798218e8c8aefbddb26a0e71bbbElliott Hughes                t.printStackTrace();
347f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            }
348320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
349320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return "unknown location";
350320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
351320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson}
352