/* * 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. */ package javax.xml.ws.spi; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.PrivilegedAction; import java.util.Properties; import org.apache.geronimo.osgi.locator.ProviderLocator; /** * This code is designed to implement the pluggability * feature and is designed to both compile and run on JDK version 1.1 and * later. The code also runs both as part of an unbundled jar file and * when bundled as part of the JDK. * <p/> * This class is duplicated for each subpackage so keep it in sync. * It is package private and therefore is not exposed as part of the JAXRPC * API. */ class FactoryFinder { /** * Set to true for debugging. */ private static final boolean debug; static { boolean b = false; try { b = Boolean.getBoolean("javax.xml.ws.spi.debug"); } catch (Throwable t) { b = false; } debug = b; } private static void debugPrintln(String msg) { if (debug) { System.err.println("JAX-WS Factory Finder: " + msg); } } /** * Figure out which ClassLoader to use. For JDK 1.2 and later use * the context ClassLoader. * * @return the <code>ClassLoader</code> * @throws ConfigurationError if this class is unable to work with the * host JDK */ private static ClassLoader findClassLoader() throws ConfigurationError { // REVIEW This doPriv block may be unnecessary because this method is private and // the caller already has a doPriv. I added the doPriv in case someone changes the // visibility of this method to non-private. ClassLoader cl = (ClassLoader) doPrivileged( new PrivilegedAction<Object>() { public Object run() { Method m = null; try { m = Thread.class.getMethod("getContextClassLoader", (Class []) null); } catch (NoSuchMethodException e) { // Assume that we are running JDK 1.1, use the current ClassLoader debugPrintln("assuming JDK 1.1"); if (FactoryFinder.class.getClassLoader() == null) { return ClassLoader.getSystemClassLoader(); } return FactoryFinder.class.getClassLoader(); } try { return (ClassLoader) m.invoke(Thread.currentThread(), (Object []) null); } catch (IllegalAccessException e) { // assert(false) throw new ConfigurationError("Unexpected IllegalAccessException", e); } catch (InvocationTargetException e) { // assert(e.getTargetException() instanceof SecurityException) throw new ConfigurationError("Unexpected InvocationTargetException", e); } } } ); return cl; } /** * Create an instance of a class using the specified * <code>ClassLoader</code>, or if that fails from the * <code>ClassLoader</code> that loaded this class. * * @param className the name of the class to instantiate * @param classLoader a <code>ClassLoader</code> to load the class from * @return a new <code>Object</code> that is an instance of the class of * the given name from the given class loader * @throws ConfigurationError if the class could not be found or * instantiated */ private static Object newInstance(String className, ClassLoader classLoader) throws ConfigurationError { final ClassLoader iClassLoader = classLoader; final String iClassName = className; // REVIEW This doPriv block may be unnecessary because this method is private and // the caller already has a doPriv. I added the doPriv in case someone changes the // visibility of this method to non-private. Object obj = doPrivileged( new PrivilegedAction<Object>() { public Object run() { try { return ProviderLocator.loadClass(iClassName, FactoryFinder.class, iClassLoader).newInstance(); } catch (ClassNotFoundException x) { throw new ConfigurationError( "Provider " + iClassName + " not found", x); } catch (Exception x) { throw new ConfigurationError( "Provider " + iClassName + " could not be instantiated: " + x, x); } } }); return obj; } /** * Finds the implementation Class object in the specified order. Main * entry point. * * @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. * @return Class object of factory, never null * @throws FactoryFinder.ConfigurationError * Package private so this code can be shared. */ static Object find(String factoryId, String fallbackClassName) throws ConfigurationError { final String iFactoryId = factoryId; final String iFallbackClassName = fallbackClassName; Object obj = doPrivileged( new PrivilegedAction<Object>() { public Object run() { debugPrintln("debug is on"); // Section 6.2.1 of the jaxws spec gives lookup order as // 1. META-INF/services definition // 2. ${java.home}/lib/jaxws.properties file // 3. System property // 4. The default implementation class ClassLoader classLoader = findClassLoader(); try { // If we are deployed into an OSGi environment, leverage it Class factoryClass = null; if (FactoryFinder.class.getClassLoader() != null) { factoryClass = FactoryFinder.class.getClassLoader().loadClass(iFactoryId); } else { factoryClass = Class.forName(iFactoryId); } Class spiClass = org.apache.servicemix.specs.locator.OsgiLocator.locate(factoryClass, iFactoryId); if (spiClass != null) { debugPrintln("Found spiClass: " + spiClass); return spiClass.newInstance(); } else { debugPrintln("No spiClass found in OSGi"); } } catch (Throwable e) { if (debug) e.printStackTrace(); } try { // check the META-INF/services definitions, and return it if // we find something. Object service = ProviderLocator.getService(iFactoryId, FactoryFinder.class, classLoader); if (service != null) { return service; } } catch (Exception ex) { if (debug) ex.printStackTrace(); } try { String factoryClassName = ProviderLocator.lookupByJREPropertyFile("lib" + File.separator + "jaxrpc.properties", iFactoryId); if (factoryClassName != null) { debugPrintln("found java.home property " + factoryClassName); return newInstance(factoryClassName, classLoader); } } catch (Exception ex) { if (debug) ex.printStackTrace(); } // Use the system property first try { String systemProp = System.getProperty(iFactoryId); if (systemProp != null) { debugPrintln("found system property " + systemProp); return newInstance(systemProp, classLoader); } } catch (SecurityException se) { } if (iFallbackClassName == null) { throw new ConfigurationError( "Provider for " + iFactoryId + " cannot be found", null); } debugPrintln("loaded from fallback value: " + iFallbackClassName); return newInstance(iFallbackClassName, classLoader); } }); return obj; } private static <T> T doPrivileged(PrivilegedAction<T> action) { SecurityManager sm = System.getSecurityManager(); if (sm == null) { return action.run(); } else { return java.security.AccessController.doPrivileged(action); } } static class ConfigurationError extends Error { // fixme: should this be refactored to use the jdk1.4 exception // wrapping? private Exception exception; /** * Construct a new instance with the specified detail string and * exception. * * @param msg the Message for this error * @param x an Exception that caused this failure, or null */ ConfigurationError(String msg, Exception x) { super(msg); this.exception = x; } Exception getException() { return exception; } } }