1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.io;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.InputStreamReader;
24 import java.io.UnsupportedEncodingException;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.net.URLEncoder;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarInputStream;
33
34 import org.apache.ibatis.logging.Log;
35 import org.apache.ibatis.logging.LogFactory;
36
37
38
39
40
41
42 public class DefaultVFS extends VFS {
43 private static final Log log = LogFactory.getLog(ResolverUtil.class);
44
45
46 private static final byte[] JAR_MAGIC = { 'P', 'K', 3, 4 };
47
48 @Override
49 public boolean isValid() {
50 return true;
51 }
52
53 @Override
54 public List<String> list(URL url, String path) throws IOException {
55 InputStream is = null;
56 try {
57 List<String> resources = new ArrayList<String>();
58
59
60
61 URL jarUrl = findJarForResource(url);
62 if (jarUrl != null) {
63 is = jarUrl.openStream();
64 if (log.isDebugEnabled()) {
65 log.debug("Listing " + url);
66 }
67 resources = listResources(new JarInputStream(is), path);
68 }
69 else {
70 List<String> children = new ArrayList<String>();
71 try {
72 if (isJar(url)) {
73
74
75 is = url.openStream();
76 JarInputStream jarInput = new JarInputStream(is);
77 if (log.isDebugEnabled()) {
78 log.debug("Listing " + url);
79 }
80 for (JarEntry entry; (entry = jarInput.getNextJarEntry()) != null;) {
81 if (log.isDebugEnabled()) {
82 log.debug("Jar entry: " + entry.getName());
83 }
84 children.add(entry.getName());
85 }
86 jarInput.close();
87 }
88 else {
89
90
91
92
93
94
95
96
97 is = url.openStream();
98 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
99 List<String> lines = new ArrayList<String>();
100 for (String line; (line = reader.readLine()) != null;) {
101 if (log.isDebugEnabled()) {
102 log.debug("Reader entry: " + line);
103 }
104 lines.add(line);
105 if (getResources(path + "/" + line).isEmpty()) {
106 lines.clear();
107 break;
108 }
109 }
110
111 if (!lines.isEmpty()) {
112 if (log.isDebugEnabled()) {
113 log.debug("Listing " + url);
114 }
115 children.addAll(lines);
116 }
117 }
118 } catch (FileNotFoundException e) {
119
120
121
122
123
124 if ("file".equals(url.getProtocol())) {
125 File file = new File(url.getFile());
126 if (log.isDebugEnabled()) {
127 log.debug("Listing directory " + file.getAbsolutePath());
128 }
129 if (file.isDirectory()) {
130 if (log.isDebugEnabled()) {
131 log.debug("Listing " + url);
132 }
133 children = Arrays.asList(file.list());
134 }
135 }
136 else {
137
138 throw e;
139 }
140 }
141
142
143 String prefix = url.toExternalForm();
144 if (!prefix.endsWith("/")) {
145 prefix = prefix + "/";
146 }
147
148
149 for (String child : children) {
150 String resourcePath = path + "/" + child;
151 resources.add(resourcePath);
152 URL childUrl = new URL(prefix + child);
153 resources.addAll(list(childUrl, resourcePath));
154 }
155 }
156
157 return resources;
158 } finally {
159 if (is != null) {
160 try {
161 is.close();
162 } catch (Exception e) {
163
164 }
165 }
166 }
167 }
168
169
170
171
172
173
174
175
176
177
178 protected List<String> listResources(JarInputStream jar, String path) throws IOException {
179
180 if (!path.startsWith("/")) {
181 path = "/" + path;
182 }
183 if (!path.endsWith("/")) {
184 path = path + "/";
185 }
186
187
188 List<String> resources = new ArrayList<String>();
189 for (JarEntry entry; (entry = jar.getNextJarEntry()) != null;) {
190 if (!entry.isDirectory()) {
191
192 String name = entry.getName();
193 if (!name.startsWith("/")) {
194 name = "/" + name;
195 }
196
197
198 if (name.startsWith(path)) {
199 if (log.isDebugEnabled()) {
200 log.debug("Found resource: " + name);
201 }
202
203 resources.add(name.substring(1));
204 }
205 }
206 }
207 return resources;
208 }
209
210
211
212
213
214
215
216
217
218
219
220 protected URL findJarForResource(URL url) throws MalformedURLException {
221 if (log.isDebugEnabled()) {
222 log.debug("Find JAR URL: " + url);
223 }
224
225
226 try {
227 for (;;) {
228 url = new URL(url.getFile());
229 if (log.isDebugEnabled()) {
230 log.debug("Inner URL: " + url);
231 }
232 }
233 } catch (MalformedURLException e) {
234
235 }
236
237
238 StringBuilder jarUrl = new StringBuilder(url.toExternalForm());
239 int index = jarUrl.lastIndexOf(".jar");
240 if (index >= 0) {
241 jarUrl.setLength(index + 4);
242 if (log.isDebugEnabled()) {
243 log.debug("Extracted JAR URL: " + jarUrl);
244 }
245 }
246 else {
247 if (log.isDebugEnabled()) {
248 log.debug("Not a JAR: " + jarUrl);
249 }
250 return null;
251 }
252
253
254 try {
255 URL testUrl = new URL(jarUrl.toString());
256 if (isJar(testUrl)) {
257 return testUrl;
258 }
259 else {
260
261 if (log.isDebugEnabled()) {
262 log.debug("Not a JAR: " + jarUrl);
263 }
264 jarUrl.replace(0, jarUrl.length(), testUrl.getFile());
265 File file = new File(jarUrl.toString());
266
267
268 if (!file.exists()) {
269 try {
270 file = new File(URLEncoder.encode(jarUrl.toString(), "UTF-8"));
271 } catch (UnsupportedEncodingException e) {
272 throw new RuntimeException("Unsupported encoding? UTF-8? That's unpossible.");
273 }
274 }
275
276 if (file.exists()) {
277 if (log.isDebugEnabled()) {
278 log.debug("Trying real file: " + file.getAbsolutePath());
279 }
280 testUrl = file.toURI().toURL();
281 if (isJar(testUrl)) {
282 return testUrl;
283 }
284 }
285 }
286 } catch (MalformedURLException e) {
287 log.warn("Invalid JAR URL: " + jarUrl);
288 }
289
290 if (log.isDebugEnabled()) {
291 log.debug("Not a JAR: " + jarUrl);
292 }
293 return null;
294 }
295
296
297
298
299
300
301
302 protected String getPackagePath(String packageName) {
303 return packageName == null ? null : packageName.replace('.', '/');
304 }
305
306
307
308
309
310
311 protected boolean isJar(URL url) {
312 return isJar(url, new byte[JAR_MAGIC.length]);
313 }
314
315
316
317
318
319
320
321
322
323 protected boolean isJar(URL url, byte[] buffer) {
324 InputStream is = null;
325 try {
326 is = url.openStream();
327 is.read(buffer, 0, JAR_MAGIC.length);
328 if (Arrays.equals(buffer, JAR_MAGIC)) {
329 if (log.isDebugEnabled()) {
330 log.debug("Found JAR: " + url);
331 }
332 return true;
333 }
334 } catch (Exception e) {
335
336 } finally {
337 if (is != null) {
338 try {
339 is.close();
340 } catch (Exception e) {
341
342 }
343 }
344 }
345
346 return false;
347 }
348 }