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 if (conn instanceof JarURLConnection)
88 {
89 try
90 {
91 jar = ((JarURLConnection) conn).getJarFile();
92 }
93
94 catch (Throwable e)
95 {
96
97
98
99
100
101 continue;
102 }
103 }
104 else
105 {
106 jar = _getAlternativeJarFile(url);
107 }
108
109 if (jar != null)
110 {
111 _searchJar(loader, result, jar, prefix, suffix);
112 }
113 else
114 {
115 if (!_searchDir(result, new File(URLDecoder.decode(url.getFile(), "UTF-8")), suffix))
116 {
117 _searchFromURL(result, prefix, suffix, url);
118 }
119 }
120 }
121 }
122
123 private static boolean _searchDir(Set<URL> result, File dir, String suffix) throws IOException
124 {
125 boolean dirExists = false;
126 if (System.getSecurityManager() != null)
127 {
128 final File finalDir = dir;
129 dirExists = (Boolean) AccessController.doPrivileged(new PrivilegedAction()
130 {
131 public Object run()
132 {
133 return finalDir.exists();
134 }
135 });
136 }
137 else
138 {
139 dirExists = dir.exists();
140 }
141 if (dirExists && dir.isDirectory())
142 {
143 for (File file : dir.listFiles())
144 {
145 String path = file.getAbsolutePath();
146 if (file.isDirectory())
147 {
148 _searchDir(result, file, suffix);
149 }
150 else if (path.endsWith(suffix))
151 {
152 result.add(file.toURI().toURL());
153 }
154 }
155
156 return true;
157 }
158
159 return false;
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 private static void _searchFromURL(Set<URL> result, String prefix, String suffix, URL url) throws IOException
177 {
178 boolean done = false;
179
180 InputStream is = _getInputStream(url);
181 if (is != null)
182 {
183 try
184 {
185 ZipInputStream zis;
186 if (is instanceof ZipInputStream)
187 {
188 zis = (ZipInputStream) is;
189 }
190 else
191 {
192 zis = new ZipInputStream(is);
193 }
194
195 try
196 {
197 ZipEntry entry = zis.getNextEntry();
198
199
200 done = entry != null;
201
202 while (entry != null)
203 {
204 String entryName = entry.getName();
205 if (entryName.endsWith(suffix))
206 {
207 result.add(new URL(url.toExternalForm() + entryName));
208 }
209
210 entry = zis.getNextEntry();
211 }
212 }
213 finally
214 {
215 zis.close();
216 }
217 }
218 catch (Exception ignore)
219 {
220 }
221 }
222
223 if (!done && prefix.length() > 0)
224 {
225
226 String urlString = url.toExternalForm() + "/";
227
228 String[] split = prefix.split("/");
229
230 prefix = _join(split, true);
231
232 String end = _join(split, false);
233 urlString = urlString.substring(0, urlString.lastIndexOf(end));
234 if (isExcludedPrefix(urlString))
235 {
236
237 return;
238 }
239 url = new URL(urlString);
240
241 _searchFromURL(result, prefix, suffix, url);
242 }
243 }
244
245
246
247
248
249
250
251
252
253
254 private static String _join(String[] tokens, boolean excludeLast)
255 {
256 StringBuilder join = new StringBuilder();
257 int length = tokens.length - (excludeLast ? 1 : 0);
258 for (int i = 0; i < length; i++)
259 {
260 join.append(tokens[i]).append("/");
261 }
262
263 return join.toString();
264 }
265
266
267
268
269
270
271
272
273 private static InputStream _getInputStream(URL url)
274 {
275 try
276 {
277 return url.openStream();
278 }
279 catch (Throwable t)
280 {
281 return null;
282 }
283 }
284
285
286
287
288
289
290 private static JarFile _getAlternativeJarFile(URL url) throws IOException
291 {
292 String urlFile = url.getFile();
293
294
295 int wlIndex = urlFile.indexOf("!/");
296
297 int oc4jIndex = urlFile.indexOf('!');
298
299 int separatorIndex = wlIndex == -1 && oc4jIndex == -1 ? -1 : wlIndex < oc4jIndex ? wlIndex : oc4jIndex;
300
301 if (separatorIndex != -1)
302 {
303 String jarFileUrl = urlFile.substring(0, separatorIndex);
304
305 if (jarFileUrl.startsWith("file:"))
306 {
307 jarFileUrl = jarFileUrl.substring("file:".length());
308 }
309
310 jarFileUrl = decodeFilesystemUrl(jarFileUrl);
311 if (isExcludedPrefix(jarFileUrl) || isExcludedSuffix(jarFileUrl))
312 {
313
314 return null;
315 }
316 return new JarFile(jarFileUrl);
317 }
318
319 return null;
320 }
321
322 private static boolean isExcludedPrefix(String url)
323 {
324 return EXCLUDED_PREFIX_SET.contains(url.substring(0, 4));
325 }
326
327 private static boolean isExcludedSuffix(String url)
328 {
329 int length = url.length();
330 return EXCLUDED_SUFFIX_SET.contains(url.substring(length - 4, length));
331 }
332
333 private static void _searchJar(ClassLoader loader, Set<URL> result, JarFile file, String prefix, String suffix)
334 throws IOException
335 {
336 Enumeration<JarEntry> e = file.entries();
337 while (e.hasMoreElements())
338 {
339 try
340 {
341 String name = e.nextElement().getName();
342 if (name.startsWith(prefix) && name.endsWith(suffix))
343 {
344 Enumeration<URL> e2 = loader.getResources(name);
345 while (e2.hasMoreElements())
346 {
347 result.add(e2.nextElement());
348 }
349 }
350 }
351 catch (Throwable t)
352 {
353
354 }
355 }
356 }
357
358 private static String decodeFilesystemUrl(String url)
359 {
360
361 String decoded = url;
362 if (url != null && url.indexOf('%') >= 0)
363 {
364 int n = url.length();
365 StringBuffer buffer = new StringBuffer();
366 ByteBuffer bytes = ByteBuffer.allocate(n);
367 for (int i = 0; i < n; )
368 {
369 if (url.charAt(i) == '%')
370 {
371 try
372 {
373 do
374 {
375 byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16);
376 bytes.put(octet);
377 i += 3;
378 } while (i < n && url.charAt(i) == '%');
379 continue;
380 }
381 catch (RuntimeException e)
382 {
383
384
385 }
386 finally
387 {
388 if (bytes.position() > 0)
389 {
390 bytes.flip();
391 buffer.append(UTF8.decode(bytes).toString());
392 bytes.clear();
393 }
394 }
395 }
396 buffer.append(url.charAt(i++));
397 }
398 decoded = buffer.toString();
399 }
400 return decoded;
401 }
402
403 }