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 */
017package org.apache.xbean.osgi.bundle.util.jar;
018
019import java.io.File;
020import java.io.FileOutputStream;
021import java.io.IOException;
022import java.io.InputStream;
023import java.net.URL;
024import java.util.Collections;
025import java.util.Enumeration;
026import java.util.LinkedList;
027import java.util.jar.JarEntry;
028import java.util.jar.JarFile;
029import java.util.jar.JarOutputStream;
030import java.util.jar.Manifest;
031import java.util.zip.ZipEntry;
032
033import org.osgi.framework.Bundle;
034
035/**
036 * @version $Rev: 937957 $ $Date: 2010-04-26 10:00:08 +0200 (lun. 26 avril 2010) $
037 */
038public 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}