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