1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.bind; 27 28 import java.lang.reflect.InvocationTargetException; 29 import java.lang.reflect.Method; 30 import java.util.Iterator; 31 import java.util.ServiceLoader; 32 import java.util.logging.Level; 33 import java.util.logging.Logger; 34 35 /** 36 * Shared ServiceLoader/FactoryFinder Utils shared among SAAJ, JAXB and JAXWS 37 * - this class must be duplicated to all those projects, but it's 38 * basically generic code and we want to have it everywhere same. 39 * 40 * @author Miroslav.Kos@oracle.com 41 */ 42 class ServiceLoaderUtil { 43 44 private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader"; 45 private static final String OSGI_SERVICE_LOADER_METHOD_NAME = "lookupProviderClasses"; 46 47 static <P, T extends Exception> P firstByServiceLoader(Class<P> spiClass, 48 Logger logger, 49 ExceptionHandler<T> handler) throws T { 50 // service discovery 51 try { 52 ServiceLoader<P> serviceLoader = ServiceLoader.load(spiClass); 53 54 for (P impl : serviceLoader) { 55 logger.fine("ServiceProvider loading Facility used; returning object [" + 56 impl.getClass().getName() + "]"); 57 58 return impl; 59 } 60 } catch (Throwable t) { 61 throw handler.createException(t, "Error while searching for service [" + spiClass.getName() + "]"); 62 } 63 return null; 64 } 65 66 static Object lookupUsingOSGiServiceLoader(String factoryId, Logger logger) { 67 68 try { 69 // Use reflection to avoid having any dependendcy on ServiceLoader class 70 Class serviceClass = Class.forName(factoryId); 71 Class target = Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME); 72 Method m = target.getMethod(OSGI_SERVICE_LOADER_METHOD_NAME, Class.class); 73 Iterator iter = ((Iterable) m.invoke(null, serviceClass)).iterator(); 74 if (iter.hasNext()) { 75 Object next = iter.next(); 76 logger.fine("Found implementation using OSGi facility; returning object [" + 77 next.getClass().getName() + "]."); 78 return next; 79 } else { 80 return null; 81 } 82 } catch (IllegalAccessException | 83 InvocationTargetException | 84 ClassNotFoundException | 85 NoSuchMethodException ignored) { 86 87 logger.log(Level.FINE, "Unable to find from OSGi: [" + factoryId + "]", ignored); 88 return null; 89 } 90 } 91 92 static void checkPackageAccess(String className) { 93 // make sure that the current thread has an access to the package of the given name. 94 SecurityManager s = System.getSecurityManager(); 95 if (s != null) { 96 int i = className.lastIndexOf('.'); 97 if (i != -1) { 98 s.checkPackageAccess(className.substring(0, i)); 99 } 100 } 101 } 102 103 static Class nullSafeLoadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { 104 if (classLoader == null) { 105 return Class.forName(className); 106 } else { 107 return classLoader.loadClass(className); 108 } 109 } 110 111 // Returns instance of required class. It checks package access (security) 112 // unless it is defaultClassname. It means if you are trying to instantiate 113 // default implementation (fallback), pass the class name to both first and second parameter. 114 static <T extends Exception> Object newInstance(String className, 115 String defaultImplClassName, 116 final ExceptionHandler<T> handler) throws T { 117 try { 118 return safeLoadClass(className, defaultImplClassName, contextClassLoader(handler)).newInstance(); 119 } catch (ClassNotFoundException x) { 120 throw handler.createException(x, "Provider " + className + " not found"); 121 } catch (Exception x) { 122 throw handler.createException(x, "Provider " + className + " could not be instantiated: " + x); 123 } 124 } 125 126 static Class safeLoadClass(String className, 127 String defaultImplClassName, 128 ClassLoader classLoader) throws ClassNotFoundException { 129 130 try { 131 checkPackageAccess(className); 132 } catch (SecurityException se) { 133 // anyone can access the platform default factory class without permission 134 if (defaultImplClassName != null && defaultImplClassName.equals(className)) { 135 return Class.forName(className); 136 } 137 // not platform default implementation ... 138 throw se; 139 } 140 return nullSafeLoadClass(className, classLoader); 141 } 142 143 static ClassLoader contextClassLoader(ExceptionHandler exceptionHandler) throws Exception { 144 try { 145 return Thread.currentThread().getContextClassLoader(); 146 } catch (Exception x) { 147 throw exceptionHandler.createException(x, x.toString()); 148 } 149 } 150 151 static abstract class ExceptionHandler<T extends Exception> { 152 153 public abstract T createException(Throwable throwable, String message); 154 155 } 156 157 }