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