1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/* 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2009 Mike Cumings 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Licensed under the Apache License, Version 2.0 (the "License"); 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage com.kenai.jbosh; 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.BufferedReader; 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.Closeable; 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.InputStream; 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.InputStreamReader; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.URL; 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.ArrayList; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.List; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.logging.Level; 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.logging.Logger; 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Utility library for use in loading services using the Jar Service 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Provider Interface (Jar SPI). This can be replaced once the minimum 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * java rev moves beyond Java 5. 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenfinal class ServiceLib { 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Logger. 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final Logger LOG = 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Logger.getLogger(ServiceLib.class.getName()); 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /////////////////////////////////////////////////////////////////////////// 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Package-private methods: 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Prevent construction. 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private ServiceLib() { 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Empty 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /////////////////////////////////////////////////////////////////////////// 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Package-private methods: 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Probe for and select an implementation of the specified service 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * type by using the a modified Jar SPI mechanism. Modified in that 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the system properties will be checked to see if there is a value 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * set for the naem of the class to be loaded. If so, that value is 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * treated as the class name of the first implementation class to be 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * attempted to be loaded. This provides a (unsupported) mechanism 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to insert other implementations. Note that the supported mechanism 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * is by properly ordering the classpath. 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return service instance 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IllegalStateException is no service implementations could be 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * instantiated 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen static <T> T loadService(Class<T> ofType) { 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<String> implClasses = loadServicesImplementations(ofType); 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (String implClass : implClasses) { 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen T result = attemptLoad(ofType, implClass); 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (result != null) { 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.FINEST)) { 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest("Selected " + ofType.getSimpleName() 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + " implementation: " 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + result.getClass().getName()); 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return result; 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw(new IllegalStateException( 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "Could not load " + ofType.getName() + " implementation")); 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /////////////////////////////////////////////////////////////////////////// 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Private methods: 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Generates a list of implementation class names by using 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the Jar SPI technique. The order in which the class names occur 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * in the service manifest is significant. 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return list of all declared implementation class names 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static List<String> loadServicesImplementations( 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final Class ofClass) { 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<String> result = new ArrayList<String>(); 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Allow a sysprop to specify the first candidate 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String override = System.getProperty(ofClass.getName()); 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (override != null) { 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen result.add(override); 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ClassLoader loader = ServiceLib.class.getClassLoader(); 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen URL url = loader.getResource("META-INF/services/" + ofClass.getName()); 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen InputStream inStream = null; 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen InputStreamReader reader = null; 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen BufferedReader bReader = null; 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen inStream = url.openStream(); 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen reader = new InputStreamReader(inStream); 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen bReader = new BufferedReader(reader); 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String line; 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen while ((line = bReader.readLine()) != null) { 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!line.matches("\\s*(#.*)?")) { 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // not a comment or blank line 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen result.add(line.trim()); 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (IOException iox) { 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.log(Level.WARNING, 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "Could not load services descriptor: " + url.toString(), 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen iox); 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } finally { 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen finalClose(bReader); 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen finalClose(reader); 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen finalClose(inStream); 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return result; 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Attempts to load the specified implementation class. 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Attempts will fail if - for example - the implementation depends 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * on a class not found on the classpath. 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param className implementation class to attempt to load 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return service instance, or {@code null} if the instance could not be 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * loaded 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static <T> T attemptLoad( 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final Class<T> ofClass, 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final String className) { 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.FINEST)) { 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.finest("Attempting service load: " + className); 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Level level; 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Exception thrown; 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Class clazz = Class.forName(className); 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!ofClass.isAssignableFrom(clazz)) { 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (LOG.isLoggable(Level.WARNING)) { 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.warning(clazz.getName() + " is not assignable to " 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + ofClass.getName()); 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return ofClass.cast(clazz.newInstance()); 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (ClassNotFoundException ex) { 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen level = Level.FINEST; 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = ex; 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (InstantiationException ex) { 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen level = Level.WARNING; 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = ex; 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (IllegalAccessException ex) { 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen level = Level.WARNING; 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown = ex; 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.log(level, 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen "Could not load " + ofClass.getSimpleName() 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen + " instance: " + className, 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen thrown); 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Check and close a closeable object, trapping and ignoring any 181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * exception that might result. 182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param closeMe the thing to close 184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static void finalClose(final Closeable closeMe) { 186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (closeMe != null) { 187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen closeMe.close(); 189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (IOException iox) { 190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen LOG.log(Level.FINEST, "Could not close: " + closeMe, iox); 191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen} 196