2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.shale.tiger.view.faces;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21
22 import java.io.File;
23 import java.io.FileFilter;
24 import java.io.IOException;
25 import java.net.JarURLConnection;
26 import java.net.URISyntaxException;
27 import java.net.URL;
28 import java.net.URLConnection;
29 import java.util.Enumeration;
30 import java.util.List;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarFile;
33
34 /***
35 * <p>Utility class with methods that support getting a recursive list of
36 * classes starting with a specific package name.</p>
37 */
38 public final class PackageInfo {
39
40 /***
41 * <p>The <code>Log</code> instance we will be using.</p>
42 */
43 private transient Log log = null;
44
45
46 /***
47 * the singleton for this class
48 */
49 private final static PackageInfo INSTANCE = new PackageInfo();
50
51
52 /***
53 * <p>Get the singleton instance of this class.</p>
54 */
55 public final static PackageInfo getInstance() {
56
57 return INSTANCE;
58
59 }
60
61
62 /***
63 * <p>Return an array of all classes, visible to our application class loader,
64 * in the specified Java package.</p>
65 *
66 * @param classes List of matching classes being accumulated
67 * @param pckgname Package name used to select matching classes
68 *
69 * @throws ClassNotFoundException
70 */
71 public Class[] getClasses(final List<Class> classes, final String pckgname)
72 throws ClassNotFoundException {
73
74 Enumeration resources;
75 ClassLoader cld;
76 String path;
77 try {
78
79
80 path = pckgname.replace('.', '/');
81
82 cld = Thread.currentThread().getContextClassLoader();
83 if (cld == null) {
84 throw new ClassNotFoundException("Can't get class loader.");
85 }
86
87
88 resources = cld.getResources(path);
89 if (resources == null || !resources.hasMoreElements()) {
90 throw new ClassNotFoundException("No resource for " + path);
91 }
92
93 } catch (NullPointerException e) {
94 throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
95 + ") does not appear to be a valid package", e);
96 } catch (IOException e) {
97 throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
98 + ") does not appear to be a valid package", e);
99 }
100
101
102 while (resources.hasMoreElements()) {
103 URL resource = (URL) resources.nextElement();
104 URLConnection connection = null;
105 try {
106 connection = resource.openConnection();
107 } catch (IOException e) {
108 throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
109 + ") does not appear to be a valid package", e);
110 }
111
112 if (connection instanceof JarURLConnection) {
113
114 JarURLConnection juc = (JarURLConnection) connection;
115 JarFile jarFile = null;
116 try {
117 jarFile = juc.getJarFile();
118 } catch (IOException e) {
119 throw(ClassNotFoundException) new ClassNotFoundException(pckgname + " (" + pckgname
120 + ") does not appear to be a valid package", e);
121 }
122 Enumeration<JarEntry> entries = jarFile.entries();
123 while (entries.hasMoreElements()) {
124 JarEntry jarEntry = entries.nextElement();
125 String entryName = jarEntry.getName();
126 if (!entryName.startsWith(path)) {
127 continue;
128 }
129 if (!entryName.toLowerCase().endsWith(".class")) {
130 continue;
131 }
132 String className = filenameToClassname(entryName);
133 loadClass(classes, cld, className);
134 }
135 } else {
136
137 File file;
138 try {
139 file = new File(connection.getURL().toURI());
140 } catch (URISyntaxException e) {
141 log().warn("error loading directory " + connection, e);
142 continue;
143 }
144
145 listFilesRecursive(classes, file, cld, pckgname);
146 }
147 }
148
149 if (classes.size() < 1) {
150 throw new ClassNotFoundException(pckgname
151 + " does not appear to be a valid package");
152 }
153
154 Class[] resolvedClasses = new Class[classes.size()];
155 classes.toArray(resolvedClasses);
156 return resolvedClasses;
157
158 }
159
160
161 /***
162 * <p>Convert a filename to a classname.</p>
163 *
164 * @param entryName Filename to be converted
165 */
166 protected String filenameToClassname(String entryName) {
167
168 return entryName.substring(0, entryName.length() - 6).replace('/', '.');
169
170 }
171
172
173 /***
174 * <p>Load the class <code>className</code> using the classloader
175 * <code>cld</code>, and add it to the list.</p>
176 *
177 * @param classes List of matching classes being accumulated
178 * @param cld ClassLoader from which to load the specified class
179 * @param className Name of the class to be loaded
180 */
181 protected void loadClass(List<Class> classes, ClassLoader cld, String className) {
182
183 try {
184 classes.add(cld.loadClass(className));
185 }
186 catch (NoClassDefFoundError e) {
187 log().warn("error loading class " + className, e);
188 } catch (ClassNotFoundException e) {
189 log().warn("error loading class " + className, e);
190 }
191
192 }
193
194
195 /***
196 * <p>Traverse a directory structure starting at <code>base</code>, adding
197 * matching files to the specified list.</p>
198 *
199 * @param classes List of matching classes being accumulated
200 * @param base Base file from which to recurse
201 * @param cld ClassLoader being searched for matching classes
202 * @param pckgname Package name used to select matching classes
203 */
204 protected void listFilesRecursive(final List<Class> classes, final File base,
205 final ClassLoader cld, final String pckgname) {
206
207 base.listFiles(new FileFilter() {
208
209 public boolean accept(File file) {
210 if (file.isDirectory()) {
211 listFilesRecursive(classes, file, cld, pckgname + "." + file.getName());
212 return false;
213 }
214 if (!file.getName().toLowerCase().endsWith(".class")) {
215 return false;
216 }
217
218 String className = filenameToClassname(pckgname + "." + file.getName());
219 loadClass(classes, cld, className);
220
221 return false;
222 }
223
224 });
225
226 }
227
228
229 /***
230 * <p>Return the <code>Log</code> instance to be used for this class,
231 * instantiating a new one if necessary.</p>
232 */
233 private Log log() {
234
235 if (log == null) {
236 log = LogFactory.getLog(PackageInfo.class);
237 }
238 return log;
239
240 }
241
242
243 }