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.io.File; 29 import java.io.FileInputStream; 30 import java.io.IOException; 31 import java.lang.reflect.InvocationTargetException; 32 import java.lang.reflect.Method; 33 import java.security.AccessController; 34 import java.security.PrivilegedAction; 35 import java.util.Iterator; 36 import java.util.Properties; 37 import java.util.ServiceLoader; 38 import java.util.logging.Level; 39 import java.util.logging.Logger; 40 41 /** 42 * Shared ServiceLoader/FactoryFinder Utils shared among SAAJ, JAXB and JAXWS 43 * - this class must be duplicated to all those projects, but it's 44 * basically generic code and we want to have it everywhere same. 45 * 46 * @author Miroslav.Kos@oracle.com 47 */ 48 class ServiceLoaderUtil { 49 50 private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader"; 51 private static final String OSGI_SERVICE_LOADER_METHOD_NAME = "lookupProviderClasses"; 52 53 static <P, T extends Exception> P firstByServiceLoader(Class<P> spiClass, Logger logger, ExceptionHandler<T> handler) throws T { 54 // service discovery 55 try { 56 ServiceLoader<P> serviceLoader = ServiceLoader.load(spiClass); 57 for (P impl : serviceLoader) { 58 logger.fine("ServiceProvider loading Facility used; returning object [" + impl.getClass().getName() + "]"); 59 return impl; 60 } 61 } catch (Throwable t) { 62 throw handler.createException(t, "Error while searching for service [" + spiClass.getName() + "]"); 63 } 64 return null; 65 } 66 67 static boolean isOsgi(Logger logger) { 68 try { 69 Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME); 70 return true; 71 } catch (ClassNotFoundException ignored) { 72 logger.log(Level.FINE, "OSGi classes not found, OSGi not available.", ignored); 73 } 74 return false; 75 } 76 77 static Object lookupUsingOSGiServiceLoader(String factoryId, Logger logger) { 78 try { 79 // Use reflection to avoid having any dependendcy on ServiceLoader class 80 Class serviceClass = Class.forName(factoryId); 81 Class target = Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME); 82 Method m = target.getMethod(OSGI_SERVICE_LOADER_METHOD_NAME, Class.class); 83 Iterator iter = ((Iterable) m.invoke(null, serviceClass)).iterator(); 84 if (iter.hasNext()) { 85 Object next = iter.next(); 86 logger.fine("Found implementation using OSGi facility; returning object [" + next.getClass().getName() + "]."); 87 return next; 88 } else { 89 return null; 90 } 91 } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException ignored) { 92 logger.log(Level.FINE, "Unable to find from OSGi: [" + factoryId + "]", ignored); 93 return null; 94 } 95 } 96 97 static String propertyFileLookup(final String configFullPath, final String factoryId) throws IOException { 98 File f = new File(configFullPath); 99 String factoryClassName = null; 100 if (f.exists()) { 101 Properties props = new Properties(); 102 FileInputStream stream = null; 103 try { 104 stream = new FileInputStream(f); 105 props.load(stream); 106 factoryClassName = props.getProperty(factoryId); 107 } finally { 108 if (stream != null) { 109 try { 110 stream.close(); 111 } catch (IOException ignored) { 112 } 113 } 114 } 115 } 116 return factoryClassName; 117 } 118 119 static void checkPackageAccess(String className) { 120 // make sure that the current thread has an access to the package of the given name. 121 SecurityManager s = System.getSecurityManager(); 122 if (s != null) { 123 int i = className.lastIndexOf('.'); 124 if (i != -1) { 125 s.checkPackageAccess(className.substring(0, i)); 126 } 127 } 128 } 129 130 static Class nullSafeLoadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { 131 if (classLoader == null) { 132 return Class.forName(className); 133 } else { 134 return classLoader.loadClass(className); 135 } 136 } 137 138 /** 139 * Returns instance of required class. It checks package access (security) unless it is defaultClassname. It means if you 140 * are trying to instantiate default implementation (fallback), pass the class name to both first and second parameter. 141 * 142 * @param className class to be instantiated 143 * @param isDefaultClassname says whether default implementation class 144 * @param handler exception handler - necessary for wrapping exceptions and logging 145 * @param <T> Type of exception being thrown (necessary to distinguish between Runtime and checked exceptions) 146 * @return instantiated object or throws Runtime/checked exception, depending on ExceptionHandler's type 147 * @throws T 148 */ 149 static <T extends Exception> Object newInstance(String className, String defaultImplClassName, final ExceptionHandler<T> handler) throws T { 150 try { 151 return safeLoadClass(className, defaultImplClassName, contextClassLoader(handler)).newInstance(); 152 } catch (ClassNotFoundException x) { 153 throw handler.createException(x, "Provider " + className + " not found"); 154 } catch (Exception x) { 155 throw handler.createException(x, "Provider " + className + " could not be instantiated: " + x); 156 } 157 } 158 159 static Class safeLoadClass(String className, String defaultImplClassName, ClassLoader classLoader) throws ClassNotFoundException { 160 try { 161 checkPackageAccess(className); 162 } catch (SecurityException se) { 163 // anyone can access the platform default factory class without permission 164 if (defaultImplClassName != null && defaultImplClassName.equals(className)) { 165 return Class.forName(className); 166 } 167 // not platform default implementation ... 168 throw se; 169 } 170 return nullSafeLoadClass(className, classLoader); 171 } 172 173 static String getJavaHomeLibConfigPath(String filename) { 174 String javah = AccessController.doPrivileged(new PrivilegedAction<String>() { 175 @Override 176 public String run() { 177 return System.getProperty("java.home"); 178 } 179 }); 180 return javah + File.separator + "lib" + File.separator + filename; 181 } 182 183 static ClassLoader contextClassLoader(ExceptionHandler exceptionHandler) throws Exception { 184 try { 185 return Thread.currentThread().getContextClassLoader(); 186 } catch (Exception x) { 187 throw exceptionHandler.createException(x, x.toString()); 188 } 189 } 190 191 static abstract class ExceptionHandler<T extends Exception> { 192 193 public abstract T createException(Throwable throwable, String message); 194 195 } 196 197 }