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