1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.shared.resource;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.net.JarURLConnection;
25 import java.net.URISyntaxException;
26 import java.net.URL;
27 import java.util.Collections;
28 import java.util.Deque;
29 import java.util.Enumeration;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.jar.JarEntry;
33 import java.util.jar.JarFile;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
36 import javax.faces.application.ResourceVisitOption;
37 import org.apache.myfaces.shared.util.ClassUtils;
38
39
40
41
42
43 public class ClassLoaderResourceLoaderIterator implements Iterator<String>
44 {
45 private Iterator<String> delegate = null;
46
47 public ClassLoaderResourceLoaderIterator(URL url, String basePath,
48 int maxDepth, ResourceVisitOption... options)
49 {
50 if (url == null)
51 {
52
53
54 delegate = null;
55 }
56 else
57 {
58 if (url.getProtocol().equals("file"))
59 {
60 try
61 {
62 File directory = new File(url.toURI());
63 delegate = new FileDepthIterator(directory, basePath, maxDepth, options);
64 }
65 catch (URISyntaxException e)
66 {
67 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName());
68 if (log.isLoggable(Level.WARNING))
69 {
70 log.log(Level.WARNING, "url "+url.toString()+" cannot be translated to uri: "
71 +e.getMessage(), e);
72 }
73 }
74 }
75 else if (isJarResourceProtocol(url.getProtocol()))
76 {
77 url = getClassLoader().getResource(basePath);
78
79 if (url != null)
80 {
81 delegate = new JarDepthIterator(url, basePath, maxDepth, options);
82 }
83 }
84 }
85 }
86
87 @Override
88 public boolean hasNext()
89 {
90 if (delegate != null)
91 {
92 return delegate.hasNext();
93 }
94 return false;
95 }
96
97 @Override
98 public String next()
99 {
100 if (delegate != null)
101 {
102 return delegate.next();
103 }
104 return null;
105 }
106
107 @Override
108 public void remove()
109 {
110
111 }
112
113 protected ClassLoader getClassLoader()
114 {
115 return ClassUtils.getContextClassLoader();
116 }
117
118 private static class JarDepthIterator implements Iterator<String>
119 {
120 private URL directory;
121 private String basePath;
122 private int maxDepth;
123 private ResourceVisitOption[] options;
124
125 private Deque<String> stack = new LinkedList<String>();
126
127 Iterator<String> iterator = null;
128
129 public JarDepthIterator(URL directory, String basePath, int maxDepth, ResourceVisitOption... options)
130 {
131 this.directory = directory;
132 this.basePath = basePath;
133 this.maxDepth = maxDepth;
134 this.options = options;
135
136 if (basePath.endsWith("/"))
137 {
138 basePath = basePath.substring(0, basePath.length()-1);
139 }
140
141 try
142 {
143 JarURLConnection conn = (JarURLConnection)directory.openConnection();
144
145 conn.setUseCaches(false);
146
147 try
148 {
149 if (conn.getJarEntry().isDirectory())
150 {
151
152 JarFile file = conn.getJarFile();
153 for (Enumeration<JarEntry> en = file.entries(); en.hasMoreElements();)
154 {
155 JarEntry entry = en.nextElement();
156 String entryName = entry.getName();
157 String path;
158
159 if (entryName.startsWith(basePath + '/'))
160 {
161 if (entryName.length() == basePath.length() + 1)
162 {
163
164 continue;
165 }
166
167 path = entryName.substring(basePath.length(), entryName.length());
168
169 if (path.endsWith("/"))
170 {
171
172 continue;
173 }
174
175
176 int depth = ResourceLoaderUtils.getDepth(path);
177 if (depth < maxDepth)
178 {
179 stack.add(path);
180 }
181 }
182 }
183 }
184 }
185 finally
186 {
187
188
189
190
191 try
192 {
193 conn.getInputStream().close();
194 }
195 catch (Exception exception)
196 {
197
198 }
199 }
200 }
201 catch (IOException e)
202 {
203
204
205 Logger log = Logger.getLogger(ClassLoaderResourceLoader.class.getName());
206 if (log.isLoggable(Level.WARNING))
207 {
208 log.log(Level.WARNING, "IOException when scanning for resource in jar file:", e);
209 }
210 }
211 iterator = stack.iterator();
212 }
213
214 @Override
215 public boolean hasNext()
216 {
217 return iterator.hasNext();
218 }
219
220 @Override
221 public String next()
222 {
223 return iterator.next();
224 }
225
226 @Override
227 public void remove()
228 {
229
230 }
231 }
232
233 private static class FileDepthIterator implements Iterator<String>
234 {
235 private File directory;
236 private String basePath;
237 private int maxDepth;
238 private ResourceVisitOption[] options;
239
240 private Deque<File> stack = new LinkedList<File>();
241 private String basePathName;
242
243 public FileDepthIterator(File directory, String basePath, int maxDepth, ResourceVisitOption... options)
244 {
245 this.directory = directory;
246 this.basePath = basePath;
247 this.maxDepth = maxDepth;
248 this.options = options;
249
250 File[] list = this.directory.listFiles();
251 Collections.addAll(stack, list);
252
253 this.basePathName = this.directory.getPath().replace(File.separatorChar, '/');
254 }
255
256 @Override
257 public boolean hasNext()
258 {
259 if (!stack.isEmpty())
260 {
261 File file = stack.peek();
262 do
263 {
264 if (file.isDirectory())
265 {
266 file = stack.pop();
267 int depth = ResourceLoaderUtils.getDepth(calculatePath(file));
268 if (depth < maxDepth)
269 {
270 File[] list = file.listFiles();
271 for (File f : list)
272 {
273 stack.add(f);
274 }
275 }
276 if (!stack.isEmpty())
277 {
278 file = stack.peek();
279 }
280 else
281 {
282 file = null;
283 }
284 }
285 }
286 while (file != null && file.isDirectory() && !stack.isEmpty());
287
288 return !stack.isEmpty();
289 }
290 return false;
291 }
292
293 @Override
294 public String next()
295 {
296 if (!stack.isEmpty())
297 {
298 File file = stack.pop();
299 do
300 {
301 if (file.isDirectory())
302 {
303 int depth = ResourceLoaderUtils.getDepth(calculatePath(file));
304 if (depth < maxDepth)
305 {
306 File[] list = file.listFiles();
307 for (File f : list)
308 {
309 stack.add(f);
310 }
311 }
312 if (!stack.isEmpty())
313 {
314 file = stack.pop();
315 }
316 else
317 {
318 file = null;
319 }
320 }
321 }
322 while (file != null && file.isDirectory() && !stack.isEmpty());
323 if (file != null)
324 {
325
326 String path = calculatePath(file);
327 return path;
328 }
329 }
330 return null;
331 }
332
333 private String calculatePath(File file)
334 {
335 return (file.getPath()).substring(this.basePathName.length()).replace(File.separatorChar, '/');
336 }
337
338 @Override
339 public void remove()
340 {
341
342 }
343 }
344
345
346
347
348
349
350
351
352
353
354
355
356 private static boolean isJarResourceProtocol(String protocol)
357 {
358
359 return "jar".equals(protocol) || "wsjar".equals(protocol) || "zip".equals(protocol);
360 }
361 }