blob: 8192e619ddea56f1cd5d5870b17f91f0a2176035 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// $Id: FactoryFinder.java 670431 2008-06-23 01:40:03Z mrglavas $
package javax.xml.parsers;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Properties;
/**
* This class is duplicated for each JAXP subpackage so keep it in
* sync. It is package private.
*
* This code is designed to implement the JAXP 1.1 spec pluggability
* feature and is designed to run on JDK version 1.1 and later including
* JVMs that perform early linking like the Microsoft JVM in IE 5. Note
* however that it must be compiled on a JDK version 1.2 or later system
* since it calls Thread#getContextClassLoader(). The code also runs both
* as part of an unbundled jar file and when bundled as part of the JDK.
*/
final class FactoryFinder {
/**
* <p>Debug flag to trace loading process.</p>
*/
private static boolean debug = false;
// Define system property "jaxp.debug" to get output
static {
// Use try/catch block to support applets, which throws
// SecurityException out of this code.
try {
String val = System.getProperty("jaxp.debug");
// Allow simply setting the prop to turn on debug
debug = val != null && (! "false".equals(val));
} catch (SecurityException se) {
debug = false;
}
}
private FactoryFinder() {}
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
*/
static Object newInstance(String className, ClassLoader cl,
boolean doFallback)
throws ConfigurationError
{
// assert(className != null);
try {
Class providerClass;
if (cl == null) {
// If classloader is null Use the bootstrap ClassLoader.
// 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();
if (cl != null) {
providerClass = cl.loadClass(className);
}
else {
providerClass = Class.forName(className);
}
} else {
throw x;
}
}
}
Object instance = providerClass.newInstance();
if (debug) 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);
}
}
/**
* Finds the implementation Class object in the specified order. Main
* entry point.
* @return Class object of factory, 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 no fallback.
*
* Package private so this code can be shared.
*/
static Object find(String factoryId, String fallbackClassName)
throws ConfigurationError
{
// Figure out which ClassLoader to use for loading the provider
// class. If there is a Context ClassLoader then use it.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
// if we have no Context ClassLoader
// so use the current ClassLoader
classLoader = FactoryFinder.class.getClassLoader();
}
if (debug) dPrint("loaded from fallback value: " + fallbackClassName);
return newInstance(fallbackClassName, classLoader, true);
}
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;
}
}
}