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