1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.util.lang.classpath;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.net.URISyntaxException;
21 import java.net.URL;
22 import java.net.URLDecoder;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Enumeration;
26 import java.util.List;
27 import java.util.jar.JarEntry;
28 import java.util.jar.JarFile;
29
30 import org.apache.commons.lang.StringUtils;
31
32 import de.smartics.util.lang.Arg;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class ClassPathDirectoryListing
48 {
49
50
51
52
53
54
55
56
57
58 private final ClassPathContext context;
59
60
61
62
63
64
65
66
67
68
69
70 public ClassPathDirectoryListing(final ClassLoader classLoader)
71 throws NullPointerException
72 {
73 this(new ClassPathContext(classLoader, null));
74 }
75
76
77
78
79
80
81
82 public ClassPathDirectoryListing(final ClassPathContext context)
83 throws NullPointerException
84 {
85 Arg.checkNotNull("context", context);
86 this.context = context;
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 public final ClassPathContext getClassPathContext()
103 {
104 return context;
105 }
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 public List<String> list(final String resourcePath)
127 throws NullPointerException, IllegalArgumentException
128 {
129 Arg.checkNotNull("resourcePath", resourcePath);
130
131 final URL resourcePathUrl = context.getResource(resourcePath);
132 if (resourcePathUrl == null)
133 {
134 throw new IllegalArgumentException("Cannot find resource '"
135 + resourcePath + "' on class path.");
136 }
137
138 final String protocol = resourcePathUrl.getProtocol();
139 if ("file".equals(protocol))
140 {
141 return handleFile(resourcePath, resourcePathUrl);
142 }
143 else if ("jar".equals(protocol))
144 {
145 return handleJar(resourcePath, resourcePathUrl);
146 }
147
148 throw new IllegalArgumentException(
149 "Protocol '" + protocol + "' is not supported to resolve resource '"
150 + resourcePath + "'.");
151 }
152
153 private List<String> handleFile(final String resourcePath,
154 final URL resourcePathUrl) throws IllegalArgumentException
155 {
156 try
157 {
158 final String[] contentsArray = new File(resourcePathUrl.toURI()).list();
159 return Arrays.asList(contentsArray);
160 }
161 catch (final URISyntaxException e)
162 {
163 throw new IllegalArgumentException(
164 "Cannot read URL derived from resource '" + resourcePath
165 + "' on the class path.", e);
166 }
167 }
168
169 private List<String> handleJar(final String resourcePath,
170 final URL resourcePathUrl) throws IllegalArgumentException
171 {
172 try
173 {
174 final List<String> contents = new ArrayList<String>();
175
176 final int separatorIndex = resourcePathUrl.getPath().indexOf('!');
177 final String jarPath =
178 resourcePathUrl.getPath().substring(5, separatorIndex);
179 final JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
180 traverseJarEntries(resourcePath, contents, jar);
181
182 return contents;
183 }
184 catch (final IOException e)
185 {
186 throw new IllegalArgumentException("Read from JAR '" + resourcePath
187 + "'.", e);
188 }
189 }
190
191 private void traverseJarEntries(final String resourcePath,
192 final List<String> contents, final JarFile jar)
193 {
194 final int resourcePathLength = resourcePath.length();
195
196 final Enumeration<JarEntry> entries = jar.entries();
197 while (entries.hasMoreElements())
198 {
199 final String name = entries.nextElement().getName();
200 if (name.startsWith(resourcePath))
201 {
202 final String entry = name.substring(resourcePathLength);
203 final String normalized = normalize(entry);
204
205 if (normalized != null && !contents.contains(normalized))
206 {
207 contents.add(normalized);
208 }
209 }
210 }
211 }
212
213 private static String normalize(final String entry)
214 {
215 if (StringUtils.isBlank(entry))
216 {
217 return null;
218 }
219
220 String normalized = entry;
221 if (normalized.charAt(0) == '/')
222 {
223 if (entry.length() == 1)
224 {
225 return null;
226 }
227 normalized = normalized.substring(1);
228 }
229
230 final int subDirIndex = normalized.indexOf('/');
231 if (subDirIndex != -1)
232 {
233 normalized = normalized.substring(0, subDirIndex);
234 }
235
236 return normalized;
237 }
238
239
240
241 }