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