/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.bpm.console.server.util; import java.io.*; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Properties; /** * Load a service class using a ordered lookup procedure * * @author Thomas.Diesler@jboss.com * @author Heiko.Braun@jboss.com * * @since 14-Dec-2006 */ public abstract class ServiceLoader { /** * This method uses the algorithm below using the JAXWS Provider as an example. * * 1. If a resource with the name of META-INF/services/javax.xml.ws.spi.Provider exists, then * its first line, if present, is used as the UTF-8 encoded name of the implementation class. * * 2. If the ${java.home}/lib/service-loader.properties file exists and it is readable by the * java.util.Properties.load(InputStream) method and it contains an entry whose key is * javax.xml.ws.spi.Provider, then the value of that entry is used as the name of the implementation class. * * 3. If a system property with the name javax.xml.ws.spi.Provider is defined, then its value is used * as the name of the implementation class. * * 4. Finally, a default implementation class name is used. */ public static Object loadService(String propertyName, String defaultFactory) { Object factory = loadFromServices(propertyName, null); if (factory == null) { factory = loadFromPropertiesFile(propertyName, null); } if (factory == null) { factory = loadFromSystemProperty(propertyName, defaultFactory); } return factory; } /** Use the Services API (as detailed in the JAR specification), if available, to determine the classname. */ public static Object loadFromServices(String propertyName, String defaultFactory) { Object factory = null; String factoryName = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); // Use the Services API (as detailed in the JAR specification), if available, to determine the classname. String filename = "META-INF/services/" + propertyName; InputStream inStream = loader.getResourceAsStream(filename); if (inStream != null) { try { BufferedReader br = new BufferedReader(new InputStreamReader(inStream, "UTF-8")); factoryName = br.readLine(); br.close(); if (factoryName != null) { Class factoryClass = loader.loadClass(factoryName); factory = factoryClass.newInstance(); } } catch (Throwable t) { throw new IllegalStateException("Failed to load " + propertyName + ": " + factoryName, t); } } // Use the default factory implementation class. if (factory == null && defaultFactory != null) { factory = loadDefault(defaultFactory); } return factory; } /** Use the system property */ public static Object loadFromSystemProperty(String propertyName, String defaultFactory) { Object factory = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); PrivilegedAction action = new PropertyAccessAction(propertyName); String factoryName = (String)AccessController.doPrivileged(action); if (factoryName != null) { try { //if(log.isDebugEnabled()) log.debug("Load from system property: " + factoryName); Class factoryClass = loader.loadClass(factoryName); factory = factoryClass.newInstance(); } catch (Throwable t) { throw new IllegalStateException("Failed to load " + propertyName + ": " + factoryName, t); } } // Use the default factory implementation class. if (factory == null && defaultFactory != null) { factory = loadDefault(defaultFactory); } return factory; } /** * Use the properties file "${java.home}/lib/service-loader.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format and contains the * fully qualified name of the implementation class with the key being the system property defined above. */ public static Object loadFromPropertiesFile(String propertyName, String defaultFactory) { Object factory = null; String factoryName = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); // Use the properties file "lib/jaxm.properties" in the JRE directory. // This configuration file is in standard java.util.Properties format and contains the fully qualified name of the implementation class with the key being the system property defined above. PrivilegedAction action = new PropertyAccessAction("java.home"); String javaHome = (String)AccessController.doPrivileged(action); File jaxmFile = new File(javaHome + "/lib/service-loader.properties"); if (jaxmFile.exists()) { try { action = new PropertyFileAccessAction(jaxmFile.getCanonicalPath()); Properties jaxmProperties = (Properties)AccessController.doPrivileged(action); factoryName = jaxmProperties.getProperty(propertyName); if (factoryName != null) { //if(log.isDebugEnabled()) log.debug("Load from " + jaxmFile + ": " + factoryName); Class factoryClass = loader.loadClass(factoryName); factory = factoryClass.newInstance(); } } catch (Throwable t) { throw new IllegalStateException("Failed to load " + propertyName + ": " + factoryName, t); } } // Use the default factory implementation class. if (factory == null && defaultFactory != null) { factory = loadDefault(defaultFactory); } return factory; } private static Object loadDefault(String defaultFactory) { Object factory = null; ClassLoader loader = Thread.currentThread().getContextClassLoader(); // Use the default factory implementation class. if (defaultFactory != null) { try { //if(log.isDebugEnabled()) log.debug("Load from default: " + factoryName); Class factoryClass = loader.loadClass(defaultFactory); factory = factoryClass.newInstance(); } catch (Throwable t) { throw new IllegalStateException("Failed to load: " + defaultFactory, t); } } return factory; } private static class PropertyAccessAction implements PrivilegedAction { private String name; PropertyAccessAction(String name) { this.name = name; } public Object run() { return System.getProperty(name); } } private static class PropertyFileAccessAction implements PrivilegedAction { private String filename; PropertyFileAccessAction(String filename) { this.filename = filename; } public Object run() { try { InputStream inStream = new FileInputStream(filename); Properties props = new Properties(); props.load(inStream); return props; } catch (IOException ex) { throw new SecurityException("Cannot load properties: " + filename, ex); } } } }