KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > adaptor > core > BundleFile


1 /*******************************************************************************
2  * Copyright (c) 2004, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.osgi.framework.adaptor.core;
13
14 import java.io.*;
15 import java.net.MalformedURLException JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.util.*;
18 import java.util.zip.ZipEntry JavaDoc;
19 import java.util.zip.ZipFile JavaDoc;
20 import org.eclipse.osgi.framework.adaptor.BundleData;
21 import org.eclipse.osgi.framework.debug.Debug;
22 import org.eclipse.osgi.framework.internal.core.Constants;
23 import org.eclipse.osgi.framework.internal.protocol.bundleresource.Handler;
24 import org.eclipse.osgi.framework.util.SecureAction;
25 import org.eclipse.osgi.util.NLS;
26 import org.osgi.framework.FrameworkEvent;
27
28 /**
29  * The BundleFile API is used by Adaptors to read resources out of an
30  * installed Bundle in the Framework.
31  * <p>
32  * Clients may extend this class.
33  * </p>
34  * @since 3.1
35  */

36 abstract public class BundleFile {
37     static final SecureAction secureAction = new SecureAction();
38     /**
39      * The File object for this BundleFile.
40      */

41     protected File JavaDoc basefile;
42
43     /**
44      * Default constructor
45      *
46      */

47     public BundleFile() {
48         // do nothing
49
}
50
51     /**
52      * BundleFile constructor
53      * @param basefile The File object where this BundleFile is
54      * persistently stored.
55      */

56     public BundleFile(File JavaDoc basefile) {
57         this.basefile = basefile;
58     }
59
60     /**
61      * Returns a File for the bundle entry specified by the path.
62      * If required the content of the bundle entry is extracted into a file
63      * on the file system.
64      * @param path The path to the entry to locate a File for.
65      * @return A File object to access the contents of the bundle entry.
66      */

67     abstract public File JavaDoc getFile(String JavaDoc path);
68
69     /**
70      * Locates a file name in this bundle and returns a BundleEntry object
71      *
72      * @param path path of the entry to locate in the bundle
73      * @return BundleEntry object or null if the file name
74      * does not exist in the bundle
75      */

76     abstract public BundleEntry getEntry(String JavaDoc path);
77
78     /**
79      * Allows to access the entries of the bundle.
80      * Since the bundle content is usually a jar, this
81      * allows to access the jar contents.
82      *
83      * GetEntryPaths allows to enumerate the content of "path".
84      * If path is a directory, it is equivalent to listing the directory
85      * contents. The returned names are either files or directories
86      * themselves. If a returned name is a directory, it finishes with a
87      * slash. If a returned name is a file, it does not finish with a slash.
88      * @param path path of the entry to locate in the bundle
89      * @return an Enumeration of Strings that indicate the paths found or
90      * null if the path does not exist.
91      */

92     abstract public Enumeration getEntryPaths(String JavaDoc path);
93
94     /**
95      * Closes the BundleFile.
96      * @throws IOException if any error occurs.
97      */

98     abstract public void close() throws IOException;
99
100     /**
101      * Opens the BundleFiles.
102      * @throws IOException if any error occurs.
103      */

104     abstract public void open() throws IOException;
105
106     /**
107      * Determines if any BundleEntries exist in the given directory path.
108      * @param dir The directory path to check existence of.
109      * @return true if the BundleFile contains entries under the given directory path;
110      * false otherwise.
111      */

112     abstract public boolean containsDir(String JavaDoc dir);
113
114     /**
115      * Returns a URL to access the contents of the entry specified by the path
116      * @param path the path to the resource
117      * @param hostBundleID the host bundle ID
118      */

119     public URL JavaDoc getResourceURL(String JavaDoc path, long hostBundleID) {
120         return getResourceURL(path, hostBundleID, 0);
121     }
122
123     /**
124      * Returns a URL to access the contents of the entry specified by the path
125      * @param path the path to the resource
126      * @param hostBundleID the host bundle ID
127      * @param index the resource index
128      */

129     public URL JavaDoc getResourceURL(String JavaDoc path, long hostBundleID, int index) {
130         BundleEntry bundleEntry = getEntry(path);
131         if (bundleEntry == null)
132             return null;
133         if (path.length() == 0 || path.charAt(0) != '/')
134             path = '/' + path;
135         try {
136             //use the constant string for the protocol to prevent duplication
137
return secureAction.getURL(Constants.OSGI_RESOURCE_URL_PROTOCOL, Long.toString(hostBundleID), index, path, new Handler(bundleEntry));
138         } catch (MalformedURLException JavaDoc e) {
139             return null;
140         }
141     }
142
143     /**
144      * A BundleFile that uses a ZipFile as it base file.
145      */

146     public static class ZipBundleFile extends BundleFile {
147         /**
148          * The bundle data
149          */

150         protected BundleData bundledata;
151         /**
152          * The zip file
153          */

154         protected ZipFile JavaDoc zipFile;
155         /**
156          * The closed flag
157          */

158         protected boolean closed = true;
159
160         /**
161          * Constructs a ZipBundle File
162          * @param basefile the base file
163          * @param bundledata the bundle data
164          * @throws IOException
165          */

166         public ZipBundleFile(File JavaDoc basefile, BundleData bundledata) throws IOException {
167             super(basefile);
168             if (!secureAction.exists(basefile))
169                 throw new IOException(NLS.bind(AdaptorMsg.ADAPTER_FILEEXIST_EXCEPTION, basefile));
170             this.bundledata = bundledata;
171             this.closed = true;
172         }
173
174         /**
175          * Checks if the zip file is open
176          * @return true if the zip file is open
177          */

178         protected boolean checkedOpen() {
179             try {
180                 return getZipFile() != null;
181             } catch (IOException e) {
182                 AbstractBundleData abstractData = (AbstractBundleData) bundledata;
183                 abstractData.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, abstractData.getBundle(), e);
184                 return false;
185             }
186         }
187
188         /**
189          * Opens the ZipFile for this bundle file
190          * @return an open ZipFile for this bundle file
191          * @throws IOException
192          */

193         protected ZipFile JavaDoc basicOpen() throws IOException {
194             return secureAction.getZipFile(this.basefile);
195         }
196
197         /**
198          * Returns an open ZipFile for this bundle file. If an open
199          * ZipFile does not exist then a new one is created and
200          * returned.
201          * @return an open ZipFile for this bundle
202          * @throws IOException
203          */

204         protected ZipFile JavaDoc getZipFile() throws IOException {
205             if (closed) {
206                 zipFile = basicOpen();
207                 closed = false;
208             }
209             return zipFile;
210         }
211
212         private ZipEntry JavaDoc getZipEntry(String JavaDoc path) {
213             if (path.length() > 0 && path.charAt(0) == '/')
214                 path = path.substring(1);
215             ZipEntry JavaDoc entry = zipFile.getEntry(path);
216             if (entry != null && entry.getSize() == 0 && !entry.isDirectory()) {
217                 // work around the directory bug see bug 83542
218
ZipEntry JavaDoc dirEntry = zipFile.getEntry(path + '/');
219                 if (dirEntry != null)
220                     entry = dirEntry;
221             }
222             return entry;
223         }
224
225         /**
226          * Extracts a directory and all sub content to disk
227          * @param dirName the directory name to extract
228          * @return the File used to extract the content to. A value
229          * of <code>null</code> is returned if the directory to extract does
230          * not exist or if content extraction is not supported.
231          */

232         protected File JavaDoc extractDirectory(String JavaDoc dirName) {
233             if (!checkedOpen())
234                 return null;
235             Enumeration entries = zipFile.entries();
236             while (entries.hasMoreElements()) {
237                 String JavaDoc entryPath = ((ZipEntry JavaDoc) entries.nextElement()).getName();
238                 if (entryPath.startsWith(dirName) && !entryPath.endsWith("/")) //$NON-NLS-1$
239
getFile(entryPath);
240             }
241             return getExtractFile(dirName);
242         }
243
244         private File JavaDoc getExtractFile(String JavaDoc entryName) {
245             if (!(bundledata instanceof AbstractBundleData))
246                 return null;
247             String JavaDoc path = ".cp"; /* put all these entries in this subdir *///$NON-NLS-1$
248
String JavaDoc name = entryName.replace('/', File.separatorChar);
249             if ((name.length() > 1) && (name.charAt(0) == File.separatorChar)) /* if name has a leading slash */
250                 path = path.concat(name);
251             else
252                 path = path + File.separator + name;
253             // first check the child generation dir
254
File JavaDoc childGenDir = ((AbstractBundleData) bundledata).getGenerationDir();
255             if (childGenDir != null) {
256                 File JavaDoc childPath = new File JavaDoc(childGenDir, path);
257                 if (childPath.exists())
258                     return childPath;
259             }
260             // now check the parent
261
File JavaDoc parentGenDir = ((AbstractBundleData) bundledata).getParentGenerationDir();
262             if (parentGenDir != null) {
263                 // there is a parent generation check if the file exists
264
File JavaDoc parentPath = new File JavaDoc(parentGenDir, path);
265                 if (parentPath.exists())
266                     // only use the parent generation file if it exists; do not extract there
267
return parentPath;
268             }
269             // did not exist in both locations; create a file for extraction.
270
File JavaDoc bundleGenerationDir = ((AbstractBundleData) bundledata).createGenerationDir();
271             /* if the generation dir exists, then we have place to cache */
272             if (bundleGenerationDir != null && bundleGenerationDir.exists())
273                 return new File JavaDoc(bundleGenerationDir, path);
274             return null;
275         }
276
277         public File JavaDoc getFile(String JavaDoc entry) {
278             if (!checkedOpen())
279                 return null;
280             ZipEntry JavaDoc zipEntry = getZipEntry(entry);
281             if (zipEntry == null) {
282                 return null;
283             }
284
285             try {
286                 File JavaDoc nested = getExtractFile(zipEntry.getName());
287                 if (nested != null) {
288                     if (nested.exists()) {
289                         /* the entry is already cached */
290                         if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
291                             Debug.println("File already present: " + nested.getPath()); //$NON-NLS-1$
292
}
293                     } else {
294                         if (zipEntry.getName().endsWith("/")) { //$NON-NLS-1$
295
if (!nested.mkdirs()) {
296                                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
297                                     Debug.println("Unable to create directory: " + nested.getPath()); //$NON-NLS-1$
298
}
299                                 throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, nested.getAbsolutePath()));
300                             }
301                             extractDirectory(zipEntry.getName());
302                         } else {
303                             InputStream in = zipFile.getInputStream(zipEntry);
304                             if (in == null)
305                                 return null;
306                             /* the entry has not been cached */
307                             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
308                                 Debug.println("Creating file: " + nested.getPath()); //$NON-NLS-1$
309
}
310                             /* create the necessary directories */
311                             File JavaDoc dir = new File JavaDoc(nested.getParent());
312                             if (!dir.exists() && !dir.mkdirs()) {
313                                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
314                                     Debug.println("Unable to create directory: " + dir.getPath()); //$NON-NLS-1$
315
}
316                                 throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, dir.getAbsolutePath()));
317                             }
318                             /* copy the entry to the cache */
319                             AbstractFrameworkAdaptor.readFile(in, nested);
320                         }
321                     }
322
323                     return nested;
324                 }
325             } catch (IOException e) {
326                 if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
327                     Debug.printStackTrace(e);
328                 }
329             }
330             return null;
331         }
332
333         public boolean containsDir(String JavaDoc dir) {
334             if (!checkedOpen())
335                 return false;
336             if (dir == null)
337                 return false;
338
339             if (dir.length() == 0)
340                 return true;
341
342             if (dir.charAt(0) == '/') {
343                 if (dir.length() == 1)
344                     return true;
345                 dir = dir.substring(1);
346             }
347
348             if (dir.length() > 0 && dir.charAt(dir.length() - 1) != '/')
349                 dir = dir + '/';
350
351             Enumeration entries = zipFile.entries();
352             ZipEntry JavaDoc zipEntry;
353             String JavaDoc entryPath;
354             while (entries.hasMoreElements()) {
355                 zipEntry = (ZipEntry JavaDoc) entries.nextElement();
356                 entryPath = zipEntry.getName();
357                 if (entryPath.startsWith(dir)) {
358                     return true;
359                 }
360             }
361             return false;
362         }
363
364         public BundleEntry getEntry(String JavaDoc path) {
365             if (!checkedOpen())
366                 return null;
367             ZipEntry JavaDoc zipEntry = getZipEntry(path);
368             if (zipEntry == null) {
369                 if (path.length() == 0 || path.charAt(path.length() - 1) == '/') {
370                     // this is a directory request lets see if any entries exist in this directory
371
if (containsDir(path))
372                         return new BundleEntry.DirZipBundleEntry(this, path);
373                 }
374                 return null;
375             }
376
377             return new BundleEntry.ZipBundleEntry(zipEntry, this);
378
379         }
380
381         public Enumeration getEntryPaths(String JavaDoc path) {
382             if (!checkedOpen())
383                 return null;
384             if (path == null) {
385                 throw new NullPointerException JavaDoc();
386             }
387
388             if (path.length() > 0 && path.charAt(0) == '/') {
389                 path = path.substring(1);
390             }
391             if (path.length() > 0 && path.charAt(path.length() - 1) != '/') {
392                 path = new StringBuffer JavaDoc(path).append("/").toString(); //$NON-NLS-1$
393
}
394
395             Vector vEntries = new Vector();
396             Enumeration entries = zipFile.entries();
397             while (entries.hasMoreElements()) {
398                 ZipEntry JavaDoc zipEntry = (ZipEntry JavaDoc) entries.nextElement();
399                 String JavaDoc entryPath = zipEntry.getName();
400                 if (entryPath.startsWith(path)) {
401                     if (path.length() < entryPath.length()) {
402                         if (entryPath.lastIndexOf('/') < path.length()) {
403                             vEntries.add(entryPath);
404                         } else {
405                             entryPath = entryPath.substring(path.length());
406                             int slash = entryPath.indexOf('/');
407                             entryPath = path + entryPath.substring(0, slash + 1);
408                             if (!vEntries.contains(entryPath)) {
409                                 vEntries.add(entryPath);
410                             }
411                         }
412                     }
413                 }
414             }
415             return vEntries.elements();
416         }
417
418         public void close() throws IOException {
419             if (!closed) {
420                 closed = true;
421                 zipFile.close();
422             }
423         }
424
425         public void open() {
426             //do nothing
427
}
428
429     }
430
431     /**
432      * A BundleFile that uses a directory as its base file.
433      */

434     public static class DirBundleFile extends BundleFile {
435
436         /**
437          * Constructs a DirBundleFile
438          * @param basefile the base file
439          * @throws IOException
440          */

441         public DirBundleFile(File JavaDoc basefile) throws IOException {
442             super(basefile);
443             if (!secureAction.exists(basefile) || !secureAction.isDirectory(basefile)) {
444                 throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_EXCEPTION, basefile));
445             }
446         }
447
448         public File JavaDoc getFile(String JavaDoc path) {
449             File JavaDoc filePath = new File JavaDoc(this.basefile, path);
450             if (secureAction.exists(filePath)) {
451                 return filePath;
452             }
453             return null;
454         }
455
456         public BundleEntry getEntry(String JavaDoc path) {
457             File JavaDoc filePath = new File JavaDoc(this.basefile, path);
458             if (!secureAction.exists(filePath)) {
459                 return null;
460             }
461             return new BundleEntry.FileBundleEntry(filePath, path);
462         }
463
464         public boolean containsDir(String JavaDoc dir) {
465             File JavaDoc dirPath = new File JavaDoc(this.basefile, dir);
466             return secureAction.exists(dirPath) && secureAction.isDirectory(dirPath);
467         }
468
469         public Enumeration getEntryPaths(final String JavaDoc path) {
470             final java.io.File JavaDoc pathFile = new java.io.File JavaDoc(basefile, path);
471             if (!secureAction.exists(pathFile))
472                 return new Enumeration() {
473                     public boolean hasMoreElements() {
474                         return false;
475                     }
476
477                     public Object JavaDoc nextElement() {
478                         throw new NoSuchElementException();
479                     }
480                 };
481             if (secureAction.isDirectory(pathFile)) {
482                 final String JavaDoc[] fileList = secureAction.list(pathFile);
483                 final String JavaDoc dirPath = path.length() == 0 || path.charAt(path.length() - 1) == '/' ? path : path + '/';
484                 return new Enumeration() {
485                     int cur = 0;
486
487                     public boolean hasMoreElements() {
488                         return fileList != null && cur < fileList.length;
489                     }
490
491                     public Object JavaDoc nextElement() {
492                         if (!hasMoreElements()) {
493                             throw new NoSuchElementException();
494                         }
495                         java.io.File JavaDoc childFile = new java.io.File JavaDoc(pathFile, fileList[cur]);
496                         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(dirPath).append(fileList[cur++]);
497                         if (secureAction.isDirectory(childFile)) {
498                             sb.append("/"); //$NON-NLS-1$
499
}
500                         return sb.toString();
501                     }
502
503                 };
504             }
505             return new Enumeration() {
506                 int cur = 0;
507
508                 public boolean hasMoreElements() {
509                     return cur < 1;
510                 }
511
512                 public Object JavaDoc nextElement() {
513                     if (cur == 0) {
514                         cur = 1;
515                         return path;
516                     }
517                     throw new NoSuchElementException();
518                 }
519             };
520         }
521
522         public void close() {
523             // nothing to do.
524
}
525
526         public void open() {
527             // nothing to do.
528
}
529     }
530
531     /**
532      * A NestedDirBundleFile uses another BundleFile as its source but
533      * accesses all of its resources relative to a nested directory within
534      * the other BundleFile object. This is used to support zipped bundles
535      * that use a Bundle-ClassPath with an nested directory specified.
536      * <p>
537      * For Example:
538      * <pre>
539      * Bundle-ClassPath: nested.jar,nesteddir/
540      * </pre>
541      */

542     public static class NestedDirBundleFile extends BundleFile {
543         BundleFile baseBundleFile;
544         String JavaDoc cp;
545
546         /**
547          * Constructs a NestedDirBundleFile
548          * @param baseBundlefile the base bundle file
549          * @param cp
550          */

551         public NestedDirBundleFile(BundleFile baseBundlefile, String JavaDoc cp) {
552             super(baseBundlefile.basefile);
553             this.baseBundleFile = baseBundlefile;
554             this.cp = cp;
555             if (cp.charAt(cp.length() - 1) != '/') {
556                 this.cp = this.cp + '/';
557             }
558         }
559
560         public void close() {
561             // do nothing.
562
}
563
564         public BundleEntry getEntry(String JavaDoc path) {
565             if (path.length() > 0 && path.charAt(0) == '/')
566                 path = path.substring(1);
567             String JavaDoc newpath = new StringBuffer JavaDoc(cp).append(path).toString();
568             return baseBundleFile.getEntry(newpath);
569         }
570
571         public boolean containsDir(String JavaDoc dir) {
572             if (dir == null)
573                 return false;
574
575             if (dir.length() > 0 && dir.charAt(0) == '/')
576                 dir = dir.substring(1);
577             String JavaDoc newdir = new StringBuffer JavaDoc(cp).append(dir).toString();
578             return baseBundleFile.containsDir(newdir);
579         }
580
581         public Enumeration getEntryPaths(String JavaDoc path) {
582             // getEntryPaths is only valid if this is a root bundle file.
583
return null;
584         }
585
586         public File JavaDoc getFile(String JavaDoc entry) {
587             // getFile is only valid if this is a root bundle file.
588
return null;
589         }
590
591         public void open() throws IOException{
592             // do nothing
593
}
594     }
595
596     /**
597      * Returns the base file for this BundleFile
598      * @return the base file for this BundleFile
599      */

600     public File JavaDoc getBaseFile() {
601         return basefile;
602     }
603 }
604
Popular Tags