1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.util;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.JarURLConnection;
25 import java.net.URL;
26 import java.net.URLConnection;
27 import java.net.URLDecoder;
28 import java.util.Arrays;
29 import java.util.Enumeration;
30 import java.util.HashSet;
31 import java.util.LinkedHashSet;
32 import java.util.Set;
33 import java.util.jar.JarEntry;
34 import java.util.jar.JarFile;
35 import java.util.zip.ZipEntry;
36 import java.util.zip.ZipInputStream;
37
38 import org.apache.myfaces.shared.util.ClassUtils;
39 import java.nio.ByteBuffer;
40 import java.nio.charset.Charset;
41 import java.security.AccessController;
42 import java.security.PrivilegedAction;
43
44
45
46
47
48
49 public final class Classpath
50 {
51 private static final Charset UTF8 = Charset.forName("UTF-8");
52 private static final Set<String> EXCLUDED_PREFIX_SET = new HashSet<String>(Arrays.asList("rar:", "sar:"));
53 private static final Set<String> EXCLUDED_SUFFIX_SET = new HashSet<String>(Arrays.asList(".rar", ".sar"));
54
55 private Classpath()
56 {
57 }
58
59 public static URL[] search(String prefix, String suffix) throws IOException
60 {
61 return search(ClassUtils.getContextClassLoader(), prefix, suffix);
62 }
63
64 public static URL[] search(ClassLoader loader, String prefix, String suffix) throws IOException
65 {
66 Set<URL> all = new LinkedHashSet<URL>();
67
68 _searchResource(all, loader, prefix, prefix, suffix);
69 _searchResource(all, loader, prefix + "MANIFEST.MF", prefix, suffix);
70
71 URL[] urlArray = (URL[]) all.toArray(new URL[all.size()]);
72
73 return urlArray;
74 }
75
76 private static void _searchResource(Set<URL> result, ClassLoader loader, String resource, String prefix,
77 String suffix) throws IOException
78 {
79 for (Enumeration<URL> urls = loader.getResources(resource); urls.hasMoreElements();)
80 {
81 URL url = urls.nextElement();
82 URLConnection conn = url.openConnection();
83 conn.setUseCaches(false);
84 conn.setDefaultUseCaches(false);
85
86 JarFile jar = null;
87 try
88 {
89 if (conn instanceof JarURLConnection)
90 {
91 jar = ((JarURLConnection) conn).getJarFile();
92 }
93 else
94 {
95 jar = _getAlternativeJarFile(url);
96 }
97
98 if (jar != null)
99 {
100 _searchJar(loader, result, jar, prefix, suffix);
101 }
102 else
103 {
104 if (!_searchDir(result, new File(URLDecoder.decode(url.getFile(), "UTF-8")), suffix))
105 {
106 _searchFromURL(result, prefix, suffix, url);
107 }
108 }
109 }
110 catch (Throwable e)
111 {
112
113
114
115
116
117 continue;
118 }
119 finally
120 {
121 if (jar != null)
122 {
123 jar.close();
124 }
125 }
126 }
127 }
128
129 private static boolean _searchDir(Set<URL> result, File dir, String suffix) throws IOException
130 {
131 boolean dirExists = false;
132 if (System.getSecurityManager() != null)
133 {
134 final File finalDir = dir;
135 dirExists = (Boolean) AccessController.doPrivileged(new PrivilegedAction()
136 {
137 public Object run()
138 {
139 return finalDir.exists();
140 }
141 });
142 }
143 else
144 {
145 dirExists = dir.exists();
146 }
147 if (dirExists && dir.isDirectory())
148 {
149 File[] dirFiles = dir.listFiles();
150 if (dirFiles != null)
151 {
152 for (File file : dirFiles)
153 {
154 String path = file.getAbsolutePath();
155 if (file.isDirectory())
156 {
157 _searchDir(result, file, suffix);
158 }
159 else if (path.endsWith(suffix))
160 {
161 result.add(file.toURI().toURL());
162 }
163 }
164 return true;
165 }
166 }
167
168 return false;
169 }
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 private static void _searchFromURL(Set<URL> result, String prefix, String suffix, URL url) throws IOException
186 {
187 boolean done = false;
188
189 InputStream is = _getInputStream(url);
190 if (is != null)
191 {
192 try
193 {
194 ZipInputStream zis;
195 if (is instanceof ZipInputStream)
196 {
197 zis = (ZipInputStream) is;
198 }
199 else
200 {
201 zis = new ZipInputStream(is);
202 }
203
204 try
205 {
206 ZipEntry entry = zis.getNextEntry();
207
208
209 done = entry != null;
210
211 while (entry != null)
212 {
213 String entryName = entry.getName();
214 if (entryName.endsWith(suffix))
215 {
216 result.add(new URL(url.toExternalForm() + entryName));
217 }
218
219 entry = zis.getNextEntry();
220 }
221 }
222 finally
223 {
224 zis.close();
225 }
226 }
227 catch (Exception ignore)
228 {
229 }
230 }
231
232 if (!done && prefix.length() > 0)
233 {
234
235 String urlString = url.toExternalForm() + "/";
236
237 String[] split = prefix.split("/");
238
239 prefix = _join(split, true);
240
241 String end = _join(split, false);
242 urlString = urlString.substring(0, urlString.lastIndexOf(end));
243 if (isExcludedPrefix(urlString))
244 {
245
246 return;
247 }
248 url = new URL(urlString);
249
250 _searchFromURL(result, prefix, suffix, url);
251 }
252 }
253
254
255
256
257
258
259
260
261
262
263 private static String _join(String[] tokens, boolean excludeLast)
264 {
265 StringBuilder join = new StringBuilder();
266 int length = tokens.length - (excludeLast ? 1 : 0);
267 for (int i = 0; i < length; i++)
268 {
269 join.append(tokens[i]).append("/");
270 }
271
272 return join.toString();
273 }
274
275
276
277
278
279
280
281
282 private static InputStream _getInputStream(URL url)
283 {
284 try
285 {
286 return url.openStream();
287 }
288 catch (Throwable t)
289 {
290 return null;
291 }
292 }
293
294
295
296
297
298
299 private static JarFile _getAlternativeJarFile(URL url) throws IOException
300 {
301 String urlFile = url.getFile();
302
303
304 int wlIndex = urlFile.indexOf("!/");
305
306 int oc4jIndex = urlFile.indexOf('!');
307
308 int separatorIndex = wlIndex == -1 && oc4jIndex == -1 ? -1 : wlIndex < oc4jIndex ? wlIndex : oc4jIndex;
309
310 if (separatorIndex != -1)
311 {
312 String jarFileUrl = urlFile.substring(0, separatorIndex);
313
314 if (jarFileUrl.startsWith("file:"))
315 {
316 jarFileUrl = jarFileUrl.substring("file:".length());
317 }
318
319 jarFileUrl = decodeFilesystemUrl(jarFileUrl);
320 if (isExcludedPrefix(jarFileUrl) || isExcludedSuffix(jarFileUrl))
321 {
322
323 return null;
324 }
325 return new JarFile(jarFileUrl);
326 }
327
328 return null;
329 }
330
331 private static boolean isExcludedPrefix(String url)
332 {
333 return EXCLUDED_PREFIX_SET.contains(url.substring(0, 4));
334 }
335
336 private static boolean isExcludedSuffix(String url)
337 {
338 int length = url.length();
339 return EXCLUDED_SUFFIX_SET.contains(url.substring(length - 4, length));
340 }
341
342 private static void _searchJar(ClassLoader loader, Set<URL> result, JarFile file, String prefix, String suffix)
343 throws IOException
344 {
345 Enumeration<JarEntry> e = file.entries();
346 while (e.hasMoreElements())
347 {
348 try
349 {
350 String name = e.nextElement().getName();
351 if (name.startsWith(prefix) && name.endsWith(suffix))
352 {
353 Enumeration<URL> e2 = loader.getResources(name);
354 while (e2.hasMoreElements())
355 {
356 result.add(e2.nextElement());
357 }
358 }
359 }
360 catch (Throwable t)
361 {
362
363 }
364 }
365 }
366
367 private static String decodeFilesystemUrl(String url)
368 {
369
370 String decoded = url;
371 if (url != null && url.indexOf('%') >= 0)
372 {
373 int n = url.length();
374 StringBuffer buffer = new StringBuffer();
375 ByteBuffer bytes = ByteBuffer.allocate(n);
376 for (int i = 0; i < n; )
377 {
378 if (url.charAt(i) == '%')
379 {
380 try
381 {
382 do
383 {
384 byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16);
385 bytes.put(octet);
386 i += 3;
387 } while (i < n && url.charAt(i) == '%');
388 continue;
389 }
390 catch (RuntimeException e)
391 {
392
393
394 }
395 finally
396 {
397 if (bytes.position() > 0)
398 {
399 bytes.flip();
400 buffer.append(UTF8.decode(bytes).toString());
401 bytes.clear();
402 }
403 }
404 }
405 buffer.append(url.charAt(i++));
406 }
407 decoded = buffer.toString();
408 }
409 return decoded;
410 }
411
412 }