| /* |
| * 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.stream; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedActionException; |
| import java.security.PrivilegedExceptionAction; |
| import java.util.Iterator; |
| import java.util.Properties; |
| import java.util.ServiceConfigurationError; |
| import java.util.ServiceLoader; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| class $FactoryFinder { |
| |
| private static final String DEFAULT_PACKAGE = "com.sun.xml.internal."; |
| |
| private static final Logger LOGGER = Logger.getLogger("javax.xml.stream"); |
| |
| final private static Properties cacheProps = new Properties(); |
| |
| private static volatile boolean firstTime = true; |
| |
| static private Class getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { |
| try { |
| if (cl == null) { |
| if (useBSClsLoader) { |
| return Class.forName(className, false, $FactoryFinder.class.getClassLoader()); |
| } else { |
| cl = getContextClassLoader(); |
| if (cl == null) { |
| throw new ClassNotFoundException(); |
| } |
| else { |
| return Class.forName(className, false, cl); |
| } |
| } |
| } |
| else { |
| return Class.forName(className, false, cl); |
| } |
| } |
| catch (ClassNotFoundException e1) { |
| if (doFallback) { |
| return Class.forName(className, false, $FactoryFinder.class.getClassLoader()); |
| } |
| else { |
| throw e1; |
| } |
| } |
| } |
| |
| |
| static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback) throws FactoryConfigurationError { |
| return newInstance(type, className, cl, doFallback, false); |
| } |
| |
| |
| static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws FactoryConfigurationError { |
| assert type != null; |
| if (System.getSecurityManager() != null) { |
| if (className != null && className.startsWith(DEFAULT_PACKAGE)) { |
| cl = null; |
| useBSClsLoader = true; |
| } |
| } |
| try { |
| Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); |
| if (!type.isAssignableFrom(providerClass)) { |
| throw new ClassCastException(className + " cannot be cast to " + type.getName()); |
| } |
| Object instance = providerClass.getConstructor().newInstance(); |
| final ClassLoader clD = cl; |
| LOGGER.fine(() -> "created new instance of " + providerClass + " using ClassLoader: " + clD); |
| return type.cast(instance); |
| } |
| catch (ClassNotFoundException x) { |
| throw new FactoryConfigurationError("Provider " + className + " not found", x); |
| } |
| catch (Exception x) { |
| throw new FactoryConfigurationError("Provider " + className + " could not be instantiated: " + x, x); |
| } |
| } |
| |
| |
| static <T> T find(Class<T> type, String fallbackClassName) throws FactoryConfigurationError { |
| return find(type, type.getName(), null, fallbackClassName); |
| } |
| |
| static <T> T find(Class<T> type, String factoryId, ClassLoader cl, String fallbackClassName) throws FactoryConfigurationError |
| { |
| try { |
| // If we are deployed into an OSGi environment, leverage it |
| Class<? extends T> spiClass = org.apache.karaf.specs.locator.OsgiLocator.locate(type, factoryId); |
| if (spiClass != null) { |
| return spiClass.getConstructor().newInstance(); |
| } |
| } catch (Throwable e) { |
| } |
| |
| try { |
| final String systemProp; |
| if (type.getName().equals(factoryId)) { |
| systemProp = getSystemProperty(factoryId); |
| } else { |
| systemProp = System.getProperty(factoryId); |
| } |
| if (systemProp != null) { |
| LOGGER.fine(() -> "found system property, value=" + systemProp); |
| return newInstance(type, systemProp, cl, true); |
| } |
| } |
| catch (SecurityException se) { |
| throw new FactoryConfigurationError("Failed to read factoryId '" + factoryId + "'", se); |
| } |
| try { |
| if (firstTime) { |
| synchronized (cacheProps) { |
| if (firstTime) { |
| firstTime = false; |
| String javaHome = getSystemProperty("java.home"); |
| String configFile; |
| configFile = javaHome + File.separator + "conf" + File.separator + "jaxp.properties"; |
| File jaxp = new File(configFile); |
| if (doesFileExist(jaxp)) { |
| cacheProps.load(getFileInputStream(jaxp)); |
| } |
| configFile = javaHome + File.separator + "conf" + File.separator + "stax.properties"; |
| File stax = new File(configFile); |
| if (doesFileExist(stax)) { |
| cacheProps.load(getFileInputStream(stax)); |
| } |
| } |
| } |
| } |
| final String factoryClassName = cacheProps.getProperty(factoryId); |
| if (factoryClassName != null) { |
| return newInstance(type, factoryClassName, cl, true); |
| } |
| } |
| catch (Exception ex) { |
| LOGGER.log(Level.FINE, "Error loading JDK properties file", ex); |
| } |
| if (type.getName().equals(factoryId)) { |
| final T provider = findServiceProvider(type, cl); |
| if (provider != null) { |
| return provider; |
| } |
| } else { |
| assert fallbackClassName == null; |
| } |
| if (fallbackClassName == null) { |
| throw new FactoryConfigurationError("Provider for " + factoryId + " cannot be found", null); |
| } |
| LOGGER.fine(() -> "loaded from fallback value: " + fallbackClassName); |
| return newInstance(type, fallbackClassName, cl, true); |
| } |
| |
| |
| private static <T> T findServiceProvider(final Class<T> type, final ClassLoader cl) { |
| try { |
| return AccessController.doPrivileged((PrivilegedAction<T>) () -> { |
| final ServiceLoader<T> serviceLoader; |
| serviceLoader = ServiceLoader.load(type, cl != null ? cl : Thread.currentThread().getContextClassLoader()); |
| final Iterator<T> iterator = serviceLoader.iterator(); |
| if (iterator.hasNext()) { |
| return iterator.next(); |
| } else { |
| return null; |
| } |
| }); |
| } catch(ServiceConfigurationError e) { |
| final RuntimeException x = new RuntimeException("Provider for " + type + " cannot be created", e); |
| throw new FactoryConfigurationError(x, x.getMessage()); |
| } |
| } |
| |
| private static ClassLoader getContextClassLoader() throws SecurityException{ |
| return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> { |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| if (cl == null) { |
| cl = ClassLoader.getSystemClassLoader(); |
| } |
| return cl; |
| }); |
| } |
| |
| private static String getSystemProperty(final String propName) { |
| return AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty(propName)); |
| } |
| |
| private static FileInputStream getFileInputStream(final File file) throws FileNotFoundException { |
| try { |
| return AccessController.doPrivileged((PrivilegedExceptionAction<FileInputStream>) () -> new FileInputStream(file)); |
| } catch (PrivilegedActionException e) { |
| throw (FileNotFoundException)e.getException(); |
| } |
| } |
| |
| private static boolean doesFileExist(final File f) { |
| return AccessController.doPrivileged((PrivilegedAction<Boolean>) f::exists); |
| } |
| } |