View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.discovery.tools;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.util.Properties;
22  
23  import org.apache.commons.discovery.DiscoveryException;
24  import org.apache.commons.discovery.Resource;
25  import org.apache.commons.discovery.ResourceIterator;
26  import org.apache.commons.discovery.resource.ClassLoaders;
27  import org.apache.commons.discovery.resource.DiscoverResources;
28  
29  
30  /***
31   * Mechanisms to locate and load a class.
32   * The load methods locate a class only.
33   * The find methods locate a class and verify that the
34   * class implements an given interface or extends a given class.
35   * 
36   * @author Richard A. Sitze
37   * @author Craig R. McClanahan
38   * @author Costin Manolache
39   */
40  public class ResourceUtils {
41      /***
42       * Get package name.
43       * Not all class loaders 'keep' package information,
44       * in which case Class.getPackage() returns null.
45       * This means that calling Class.getPackage().getName()
46       * is unreliable at best.
47       */
48      public static String getPackageName(Class clazz) {
49          Package clazzPackage = clazz.getPackage();
50          String packageName;
51          if (clazzPackage != null) {
52              packageName = clazzPackage.getName();
53          } else {
54              String clazzName = clazz.getName();
55              packageName = new String(clazzName.toCharArray(), 0, clazzName.lastIndexOf('.'));
56          }
57          return</strong> packageName;
58      }
59      
60      
61      /***
62       * Load the resource <code>resourceName</code>.
63       * Try each classloader in succession,
64       * until first succeeds, or all fail.
65       * If all fail and <code>resouceName</code> is not absolute
66       * (doesn't start with '/' character), then retry with
67       * <code>packageName/resourceName</code> after changing all
68       * '.' to '/'.
69       * 
70       * @param resourceName The name of the resource to load.
71       */
72      public static Resource getResource(Class spi,
73                                         String resourceName,
74                                         ClassLoaders loaders)
75          throws DiscoveryException
76      {
77          DiscoverResources explorer = new DiscoverResources(loaders);
78          ResourceIterator resources = explorer.findResources(resourceName);
79          
80          if (spi != null  &&
81              !resources.hasNext()  &&
82              resourceName.charAt(0) != '/')
83          {
84              /***
85               * If we didn't find the resource, and if the resourceName
86               * isn't an 'absolute' path name, then qualify with
87               * package name of the spi.
88               */
89              resourceName = getPackageName(spi).replace('.','/') + "/" + resourceName;
90              resources = explorer.findResources(resourceName);
91          }
92          
93          return resources.hasNext()
94                 ? resources.nextResource()
95                 : null;
96      }
97      
98      /***
99       * Load named property file, optionally qualifed by spi's package name
100      * as per Class.getResource.
101      * 
102      * A property file is loaded using the following sequence of class loaders:
103      *   <ul>
104      *     <li>Thread Context Class Loader</li>
105      *     <li>DiscoverSingleton's Caller's Class Loader</li>
106      *     <li>SPI's Class Loader</li>
107      *     <li>DiscoverSingleton's (this class) Class Loader</li>
108      *     <li>System Class Loader</li>
109      *   </ul>
110      * 
111      * @param propertiesFileName The property file name.
112      * 
113      * @return Instance of a class implementing the SPI.
114      * 
115      * @exception DiscoveryException Thrown if the name of a class implementing
116      *            the SPI cannot be found, if the class cannot be loaded and
117      *            instantiated, or if the resulting class does not implement
118      *            (or extend) the SPI.
119      */    
120     public static Properties loadProperties(Class spi,
121                                             String propertiesFileName,
122                                             ClassLoaders classLoaders)
123         throws DiscoveryException
124     {
125         Properties properties = null;
126         
127         if (propertiesFileName != null) {
128             try {
129                 Resource resource = getResource(spi, propertiesFileName, classLoaders);
130                 if (resource != null) {
131                     InputStream stream = resource.getResourceAsStream();
132         
133                     if (stream != null) {
134                         properties = new Properties();
135                         try {
136                             properties.load(stream);
137                         } finally {
138                             stream.close();
139                         }
140                     }
141                 }
142             } catch (IOException e) {
143                 // ignore
144             } catch (SecurityException e) {
145                 // ignore
146             }
147         }
148         
149         return properties;
150     }
151 }