1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.osgi.io;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.net.URLConnection;
26 import java.util.Enumeration;
27 import java.util.LinkedHashSet;
28 import java.util.Set;
29
30 import org.osgi.framework.Bundle;
31 import org.springframework.core.io.AbstractResource;
32 import org.springframework.core.io.ContextResource;
33 import org.springframework.core.io.Resource;
34 import org.springframework.core.io.ResourceLoader;
35 import org.springframework.osgi.io.internal.OsgiResourceUtils;
36 import org.springframework.util.Assert;
37 import org.springframework.util.ObjectUtils;
38 import org.springframework.util.ResourceUtils;
39 import org.springframework.util.StringUtils;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public class OsgiBundleResource extends AbstractResource implements ContextResource {
82
83
84
85
86
87
88 public static final String BUNDLE_URL_PREFIX = "osgibundle:";
89
90
91
92
93
94 public static final String BUNDLE_JAR_URL_PREFIX = "osgibundlejar:";
95
96 private static final char PREFIX_SEPARATOR = ':';
97
98 private static final String ABSOLUTE_PATH_PREFIX = "/";
99
100 private final Bundle bundle;
101
102 private final String path;
103
104
105 private final String pathWithoutPrefix;
106
107
108 private int searchType = OsgiResourceUtils.PREFIX_TYPE_NOT_SPECIFIED;
109
110
111
112
113
114
115
116
117
118 public OsgiBundleResource(Bundle bundle, String path) {
119 Assert.notNull(bundle, "Bundle must not be null");
120 this.bundle = bundle;
121
122
123 Assert.notNull(path, "Path must not be null");
124
125 this.path = StringUtils.cleanPath(path);
126
127 this.searchType = OsgiResourceUtils.getSearchType(this.path);
128
129 switch (this.searchType) {
130 case OsgiResourceUtils.PREFIX_TYPE_NOT_SPECIFIED:
131 pathWithoutPrefix = path;
132 break;
133 case OsgiResourceUtils.PREFIX_TYPE_BUNDLE_SPACE:
134 pathWithoutPrefix = path.substring(BUNDLE_URL_PREFIX.length());
135 break;
136 case OsgiResourceUtils.PREFIX_TYPE_BUNDLE_JAR:
137 pathWithoutPrefix = path.substring(BUNDLE_JAR_URL_PREFIX.length());
138 break;
139 case OsgiResourceUtils.PREFIX_TYPE_CLASS_SPACE:
140 pathWithoutPrefix = path.substring(ResourceLoader.CLASSPATH_URL_PREFIX.length());
141 break;
142
143 default:
144 pathWithoutPrefix = null;
145 }
146 }
147
148
149
150
151
152
153 final String getPath() {
154 return path;
155 }
156
157
158
159
160
161
162 final Bundle getBundle() {
163 return bundle;
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180 public InputStream getInputStream() throws IOException {
181 URLConnection con = getURL().openConnection();
182 con.setUseCaches(false);
183 return con.getInputStream();
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 public URL getURL() throws IOException {
200 ContextResource res = null;
201 URL url = null;
202
203 switch (searchType) {
204
205 case OsgiResourceUtils.PREFIX_TYPE_NOT_SPECIFIED:
206 res = getResourceFromBundleSpace(pathWithoutPrefix);
207 break;
208 case OsgiResourceUtils.PREFIX_TYPE_BUNDLE_SPACE:
209 res = getResourceFromBundleSpace(pathWithoutPrefix);
210 break;
211 case OsgiResourceUtils.PREFIX_TYPE_BUNDLE_JAR:
212 url = getResourceFromBundleJar(pathWithoutPrefix);
213 break;
214 case OsgiResourceUtils.PREFIX_TYPE_CLASS_SPACE:
215 url = getResourceFromBundleClasspath(pathWithoutPrefix);
216 break;
217
218 default:
219
220 url = new URL(path);
221 break;
222 }
223
224 if (res != null) {
225 url = res.getURL();
226 }
227
228 if (url == null) {
229 throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
230 }
231
232 return url;
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246
247 ContextResource getResourceFromBundleSpace(String bundlePath) throws IOException {
248 ContextResource[] res = getAllUrlsFromBundleSpace(bundlePath);
249 return (ObjectUtils.isEmpty(res) ? null : res[0]);
250 }
251
252
253
254
255
256
257
258
259
260
261
262 URL getResourceFromBundleJar(String bundlePath) throws IOException {
263 return bundle.getEntry(bundlePath);
264 }
265
266
267
268
269
270
271
272
273
274
275 URL getResourceFromBundleClasspath(String bundlePath) {
276 return bundle.getResource(bundlePath);
277 }
278
279
280
281
282
283
284
285 boolean isRelativePath(String locationPath) {
286 return ((locationPath.indexOf(PREFIX_SEPARATOR) == -1) && !locationPath.startsWith(ABSOLUTE_PATH_PREFIX));
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300 public Resource createRelative(String relativePath) {
301 String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
302 return new OsgiBundleResource(this.bundle, pathToUse);
303 }
304
305
306
307
308
309
310
311
312 public String getFilename() {
313 return StringUtils.getFilename(this.path);
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327 public File getFile() throws IOException {
328
329 if (searchType != OsgiResourceUtils.PREFIX_TYPE_UNKNOWN) {
330 String bundleLocation = bundle.getLocation();
331 int prefixIndex = bundleLocation.indexOf(ResourceUtils.FILE_URL_PREFIX);
332 if (prefixIndex > -1) {
333 bundleLocation = bundleLocation.substring(prefixIndex + ResourceUtils.FILE_URL_PREFIX.length());
334 }
335 File file = new File(bundleLocation, path);
336 if (file.exists()) {
337 return file;
338 }
339
340 }
341
342 try {
343 URL url = new URL(path);
344 File file = new File(url.getPath());
345 if (file.exists())
346 return file;
347 }
348 catch (MalformedURLException mue) {
349
350 }
351
352 return super.getFile();
353 }
354
355
356
357
358
359 public String getDescription() {
360 StringBuffer buf = new StringBuffer();
361 buf.append("OSGi resource[");
362 buf.append(this.path);
363 buf.append("|bnd.id=");
364 buf.append(bundle.getBundleId());
365 buf.append("|bnd.sym=");
366 buf.append(bundle.getSymbolicName());
367 buf.append("]");
368
369 return buf.toString();
370 }
371
372
373
374
375
376 public boolean equals(Object obj) {
377 if (obj == this) {
378 return true;
379 }
380 if (obj instanceof OsgiBundleResource) {
381 OsgiBundleResource otherRes = (OsgiBundleResource) obj;
382 return (this.path.equals(otherRes.path) && ObjectUtils.nullSafeEquals(this.bundle, otherRes.bundle));
383 }
384 return false;
385 }
386
387
388
389
390
391 public int hashCode() {
392 return this.path.hashCode();
393 }
394
395 public long lastModified() throws IOException {
396 URLConnection con = getURL().openConnection();
397 con.setUseCaches(false);
398 long time = con.getLastModified();
399
400 if (time == 0) {
401 if (OsgiResourceUtils.PREFIX_TYPE_BUNDLE_JAR == searchType)
402 return bundle.getLastModified();
403 }
404
405 return time;
406 }
407
408
409
410
411 int getSearchType() {
412 return searchType;
413 }
414
415
416
417
418
419
420
421
422
423
424 ContextResource[] getAllUrlsFromBundleSpace(String location) throws IOException {
425 if (bundle == null)
426 throw new IllegalArgumentException(
427 "cannot locate items in bundle-space w/o a bundle; specify one when creating this resolver");
428
429 Assert.notNull(location);
430 Set resources = new LinkedHashSet(5);
431
432 location = StringUtils.cleanPath(location);
433 location = OsgiResourceUtils.stripPrefix(location);
434
435 if (!StringUtils.hasText(location))
436 location = OsgiResourceUtils.FOLDER_DELIMITER;
437
438
439 if (OsgiResourceUtils.FOLDER_DELIMITER.equals(location)) {
440
441
442
443
444
445
446
447
448
449 Enumeration candidates = bundle.findEntries("/", null, false);
450
451
452
453 while (candidates != null && candidates.hasMoreElements()) {
454
455 URL url = (URL) candidates.nextElement();
456
457
458
459
460 String rootPath = OsgiResourceUtils.findUpperFolder(url.toExternalForm());
461 resources.add(new UrlContextResource(rootPath));
462 }
463 }
464 else {
465
466 if (location.startsWith(OsgiResourceUtils.FOLDER_DELIMITER))
467 location = location.substring(1);
468
469 if (location.endsWith(OsgiResourceUtils.FOLDER_DELIMITER))
470 location = location.substring(0, location.length() - 1);
471
472
473 boolean hasFolder = (location.indexOf(OsgiResourceUtils.FOLDER_DELIMITER) != -1);
474
475 String path = (hasFolder ? location : OsgiResourceUtils.FOLDER_DELIMITER);
476 String file = (hasFolder ? null : location);
477
478
479 int separatorIndex = location.lastIndexOf(OsgiResourceUtils.FOLDER_DELIMITER);
480
481 if (separatorIndex > -1 && separatorIndex + 1 < location.length()) {
482
483 path = location.substring(0, separatorIndex);
484
485
486 if (separatorIndex + 1 < location.length())
487 file = location.substring(separatorIndex + 1);
488 }
489
490 Enumeration candidates = bundle.findEntries(path, file, false);
491
492 String contextPath = OsgiResourceUtils.FOLDER_DELIMITER + location;
493
494 while (candidates != null && candidates.hasMoreElements()) {
495 resources.add(new UrlContextResource((URL) candidates.nextElement(), contextPath));
496 }
497 }
498
499 return (ContextResource[]) resources.toArray(new ContextResource[resources.size()]);
500 }
501
502
503 public String getPathWithinContext() {
504 return pathWithoutPrefix;
505 }
506
507
508
509
510
511
512
513
514
515
516
517
518 public boolean exists() {
519 try {
520 InputStream is = getInputStream();
521 is.close();
522 return true;
523 }
524 catch (Throwable isEx) {
525 return false;
526 }
527 }
528 }