001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.xbean.osgi.bundle.util.jar;
018    
019    import java.io.File;
020    import java.io.FileOutputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.net.URL;
024    import java.util.Collections;
025    import java.util.Enumeration;
026    import java.util.LinkedList;
027    import java.util.jar.JarEntry;
028    import java.util.jar.JarFile;
029    import java.util.jar.JarOutputStream;
030    import java.util.jar.Manifest;
031    import java.util.zip.ZipEntry;
032    
033    import org.osgi.framework.Bundle;
034    
035    /**
036     * @version $Rev: 937957 $ $Date: 2010-04-26 10:00:08 +0200 (Mon, 26 Apr 2010) $
037     */
038    public class BundleJarFile extends JarFile {
039        
040        private static final File DUMMY_JAR_FILE;
041    
042        static {
043            try {
044                DUMMY_JAR_FILE = createTempFile();
045                new JarOutputStream(new FileOutputStream(BundleJarFile.DUMMY_JAR_FILE), new Manifest()).close();
046            } catch (IOException e) {
047                throw new ExceptionInInitializerError(e);
048            }
049        }
050        private final Bundle bundle;
051        private boolean manifestLoaded = false;
052        private Manifest manifest;
053        
054        public BundleJarFile(Bundle bundle) throws IOException {
055            super(DUMMY_JAR_FILE);
056            this.bundle = bundle;
057        }
058    
059        public Bundle getBundle() {
060            return bundle;
061        }
062    
063        public Manifest getManifest() throws IOException {        
064            if (!manifestLoaded) {
065                URL manifestURL = bundle.getEntry("META-INF/MANIFEST.MF");
066                if (manifestURL != null) {
067                    InputStream in = null;
068                    try {
069                        in = manifestURL.openStream();
070                        manifest = new Manifest(in);
071                    } finally {
072                        if (in != null) {
073                            try {
074                                in.close();
075                            } catch (IOException e) {
076                                // ignore
077                            }
078                        }
079                    }
080                }
081                manifestLoaded = true;
082            }
083            return manifest;
084        }
085    
086        public BundleJarEntry getBundleJarEntry(String name) {
087            URL url = bundle.getEntry(name);
088            if (url == null) {
089                return null;
090            }
091            return new BundleJarEntry(name, url, getManifestSafe());
092        }
093    
094        public JarEntry getJarEntry(String name) {
095            return getBundleJarEntry(name);
096        }
097    
098        public ZipEntry getEntry(String name) {
099            return getBundleJarEntry(name);
100        }
101    
102        public Enumeration entries() {
103            Manifest manifest = getManifestSafe();
104            Enumeration e = bundle.findEntries("/", "*", true);
105            LinkedList entries = new LinkedList();
106            while (e.hasMoreElements()) {
107                URL entryURL = (URL) e.nextElement();
108                entries.add(new BundleJarEntry(entryURL.getPath(), entryURL, manifest));
109            }
110            return Collections.enumeration(entries);
111        }
112    
113        public InputStream getInputStream(ZipEntry zipEntry) throws IOException {
114            BundleJarEntry entry;
115            if (zipEntry instanceof BundleJarEntry) {
116                entry = (BundleJarEntry) zipEntry;
117            } else {
118                entry = getBundleJarEntry(zipEntry.getName());
119            }
120    
121            if (entry == null) {
122                throw new IOException("Entry not found: name=" + zipEntry.getName());
123            } else if (entry.isDirectory()) {
124                return new EmptyInputStream();
125            } else {
126                return entry.getEntryURL().openStream();
127            }
128        }
129    
130        public String getName() {
131            return bundle.getSymbolicName();
132        }
133    
134        public int size() {
135            return -1;
136        }
137    
138        public void close() throws IOException {
139        }
140    
141        private Manifest getManifestSafe() {
142            Manifest manifest = null;
143            try {
144                manifest = getManifest();
145            } catch (IOException e) {
146                // ignore
147            }
148            return manifest;
149        }
150    
151        // be careful to clean up the temp file... we tell the vm to delete this on exit
152        // but VMs can't be trusted to acutally delete the file
153        private static File createTempFile() throws IOException {
154            File tempFile = File.createTempFile("geronimo-fileutils", ".tmpfile");
155            tempFile.deleteOnExit();
156            return tempFile;
157        }
158    
159    
160        private static final class EmptyInputStream extends InputStream {
161    
162             public int read() {
163                 return -1;
164             }
165    
166             public int read(byte b[]) {
167                 return -1;
168             }
169    
170             public int read(byte b[], int off, int len) {
171                 return -1;
172             }
173    
174             public long skip(long n) {
175                 return 0;
176             }
177    
178             public int available() {
179                 return 0;
180             }
181    
182             public void close() {
183             }
184    
185             public synchronized void mark(int readlimit) {
186             }
187    
188             public synchronized void reset() {
189             }
190    
191             public boolean markSupported() {
192                 return false;
193             }
194         }
195    
196    }