001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.discovery.tools; 018 019 import java.io.IOException; 020 import java.io.InputStream; 021 import java.util.Properties; 022 023 import org.apache.commons.discovery.DiscoveryException; 024 import org.apache.commons.discovery.Resource; 025 import org.apache.commons.discovery.ResourceIterator; 026 import org.apache.commons.discovery.resource.ClassLoaders; 027 import org.apache.commons.discovery.resource.DiscoverResources; 028 029 /** 030 * Mechanisms to locate and load a class. 031 * 032 * The load methods locate a class only. 033 * The find methods locate a class and verify that the 034 * class implements an given interface or extends a given class. 035 */ 036 public class ResourceUtils { 037 038 /** 039 * Get package name. 040 * 041 * Not all class loaders 'keep' package information, 042 * in which case Class.getPackage() returns null. 043 * This means that calling Class.getPackage().getName() 044 * is unreliable at best. 045 * 046 * @param clazz The class from which the package has to be extracted 047 * @return The string representation of the input class package 048 */ 049 public static String getPackageName(Class<?> clazz) { 050 Package clazzPackage = clazz.getPackage(); 051 String packageName; 052 if (clazzPackage != null) { 053 packageName = clazzPackage.getName(); 054 } else { 055 String clazzName = clazz.getName(); 056 packageName = new String(clazzName.toCharArray(), 0, clazzName.lastIndexOf('.')); 057 } 058 return packageName; 059 } 060 061 /** 062 * Load the resource <code>resourceName</code>. 063 * 064 * Try each classloader in succession, 065 * until first succeeds, or all fail. 066 * If all fail and <code>resouceName</code> is not absolute 067 * (doesn't start with '/' character), then retry with 068 * <code>packageName/resourceName</code> after changing all 069 * '.' to '/'. 070 * 071 * @param spi The SPI type 072 * @param resourceName The name of the resource to load. 073 * @param loaders the class loaders holder 074 * @return The discovered {@link Resource} instance 075 * @throws DiscoveryException if the class implementing 076 * the SPI cannot be found, cannot be loaded and 077 * instantiated, or if the resulting class does not implement 078 * (or extend) the SPI 079 */ 080 public static Resource getResource(Class<?> spi, 081 String resourceName, 082 ClassLoaders loaders) throws DiscoveryException { 083 DiscoverResources explorer = new DiscoverResources(loaders); 084 ResourceIterator resources = explorer.findResources(resourceName); 085 086 if (spi != null && 087 !resources.hasNext() && 088 resourceName.charAt(0) != '/') { 089 /** 090 * If we didn't find the resource, and if the resourceName 091 * isn't an 'absolute' path name, then qualify with 092 * package name of the spi. 093 */ 094 resourceName = getPackageName(spi).replace('.','/') + "/" + resourceName; 095 resources = explorer.findResources(resourceName); 096 } 097 098 return resources.hasNext() 099 ? resources.nextResource() 100 : null; 101 } 102 103 /** 104 * Load named property file, optionally qualified by spi's package name 105 * as per Class.getResource. 106 * 107 * A property file is loaded using the following sequence of class loaders: 108 * <ul> 109 * <li>Thread Context Class Loader</li> 110 * <li>DiscoverSingleton's Caller's Class Loader</li> 111 * <li>SPI's Class Loader</li> 112 * <li>DiscoverSingleton's (this class) Class Loader</li> 113 * <li>System Class Loader</li> 114 * </ul> 115 * 116 * @param spi The SPI type 117 * @param propertiesFileName The property file name. 118 * @param classLoaders The class loaders holder 119 * @return The loaded named property file, in {@code Properties} format 120 * @throws DiscoveryException Thrown if the name of a class implementing 121 * the SPI cannot be found, if the class cannot be loaded and 122 * instantiated, or if the resulting class does not implement 123 * (or extend) the SPI. 124 */ 125 public static Properties loadProperties(Class<?> spi, 126 String propertiesFileName, 127 ClassLoaders classLoaders) throws DiscoveryException { 128 Properties properties = null; 129 130 if (propertiesFileName != null) { 131 try { 132 Resource resource = getResource(spi, propertiesFileName, classLoaders); 133 if (resource != null) { 134 InputStream stream = resource.getResourceAsStream(); 135 136 if (stream != null) { 137 properties = new Properties(); 138 try { 139 properties.load(stream); 140 } finally { 141 stream.close(); 142 } 143 } 144 } 145 } catch (IOException e) { 146 // ignore 147 } catch (SecurityException e) { 148 // ignore 149 } 150 } 151 152 return properties; 153 } 154 155 }