blob: 204c2dcfd57c86b1135e2b3c7d20e78eabbfeb01 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.baseadaptor.bundlefile;
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.osgi.baseadaptor.BaseData;
import org.eclipse.osgi.framework.debug.Debug;
import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg;
import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.FrameworkEvent;
/**
* A BundleFile that uses a ZipFile as it base file.
* @since 3.2
*/
public class ZipBundleFile extends BundleFile {
protected static MRUBundleFileList mruList = new MRUBundleFileList();
/**
* The bundle data
*/
protected BaseData bundledata;
/**
* The zip file
*/
protected ZipFile zipFile;
/**
* The closed flag
*/
protected boolean closed = true;
/**
* Constructs a ZipBundle File
* @param basefile the base file
* @param bundledata the bundle data
* @throws IOException
*/
public ZipBundleFile(File basefile, BaseData bundledata) throws IOException {
super(basefile);
if (!BundleFile.secureAction.exists(basefile))
throw new IOException(NLS.bind(AdaptorMsg.ADAPTER_FILEEXIST_EXCEPTION, basefile));
this.bundledata = bundledata;
this.closed = true;
}
/**
* Checks if the zip file is open
* @return true if the zip file is open
*/
protected boolean checkedOpen() {
try {
return getZipFile() != null;
} catch (IOException e) {
if (bundledata != null)
bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), e);
return false;
}
}
/**
* Opens the ZipFile for this bundle file
* @return an open ZipFile for this bundle file
* @throws IOException
*/
protected ZipFile basicOpen() throws IOException {
return BundleFile.secureAction.getZipFile(this.basefile);
}
/**
* Returns an open ZipFile for this bundle file. If an open
* ZipFile does not exist then a new one is created and
* returned.
* @return an open ZipFile for this bundle
* @throws IOException
*/
protected synchronized ZipFile getZipFile() throws IOException {
if (closed) {
mruList.add(this);
zipFile = basicOpen();
closed = false;
} else
mruList.use(this);
return zipFile;
}
/**
* Returns a ZipEntry for the bundle file. Must be called while synchronizing on this object.
* This method does not ensure that the ZipFile is opened. Callers may need to call getZipfile() prior to calling this
* method.
* @param path the path to an entry
* @return a ZipEntry or null if the entry does not exist
*/
protected ZipEntry getZipEntry(String path) {
if (path.length() > 0 && path.charAt(0) == '/')
path = path.substring(1);
ZipEntry entry = zipFile.getEntry(path);
if (entry != null && entry.getSize() == 0 && !entry.isDirectory()) {
// work around the directory bug see bug 83542
ZipEntry dirEntry = zipFile.getEntry(path + '/');
if (dirEntry != null)
entry = dirEntry;
}
return entry;
}
/**
* Extracts a directory and all sub content to disk
* @param dirName the directory name to extract
* @return the File used to extract the content to. A value
* of <code>null</code> is returned if the directory to extract does
* not exist or if content extraction is not supported.
*/
protected synchronized File extractDirectory(String dirName) {
if (!checkedOpen())
return null;
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements()) {
String entryPath = ((ZipEntry) entries.nextElement()).getName();
if (entryPath.startsWith(dirName) && !entryPath.endsWith("/")) //$NON-NLS-1$
getFile(entryPath, false);
}
return getExtractFile(dirName);
}
protected File getExtractFile(String entryName) {
if (bundledata == null)
return null;
String path = ".cp"; /* put all these entries in this subdir *///$NON-NLS-1$
String name = entryName.replace('/', File.separatorChar);
if ((name.length() > 1) && (name.charAt(0) == File.separatorChar)) /* if name has a leading slash */
path = path.concat(name);
else
path = path + File.separator + name;
return bundledata.getExtractFile(path);
}
public synchronized File getFile(String entry, boolean nativeCode) {
if (!checkedOpen())
return null;
ZipEntry zipEntry = getZipEntry(entry);
if (zipEntry == null)
return null;
try {
File nested = getExtractFile(zipEntry.getName());
if (nested != null) {
if (nested.exists()) {
/* the entry is already cached */
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.println("File already present: " + nested.getPath()); //$NON-NLS-1$
if (nested.isDirectory())
// must ensure the complete directory is extracted (bug 182585)
extractDirectory(zipEntry.getName());
} else {
if (zipEntry.getName().endsWith("/")) { //$NON-NLS-1$
if (!nested.mkdirs()) {
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.println("Unable to create directory: " + nested.getPath()); //$NON-NLS-1$
throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, nested.getAbsolutePath()));
}
extractDirectory(zipEntry.getName());
} else {
InputStream in = zipFile.getInputStream(zipEntry);
if (in == null)
return null;
/* the entry has not been cached */
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.println("Creating file: " + nested.getPath()); //$NON-NLS-1$
/* create the necessary directories */
File dir = new File(nested.getParent());
if (!dir.exists() && !dir.mkdirs()) {
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.println("Unable to create directory: " + dir.getPath()); //$NON-NLS-1$
throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, dir.getAbsolutePath()));
}
/* copy the entry to the cache */
AdaptorUtil.readFile(in, nested);
if (nativeCode)
setPermissions(nested);
}
}
return nested;
}
} catch (IOException e) {
if (Debug.DEBUG && Debug.DEBUG_GENERAL)
Debug.printStackTrace(e);
}
return null;
}
public synchronized boolean containsDir(String dir) {
if (!checkedOpen())
return false;
if (dir == null)
return false;
if (dir.length() == 0)
return true;
if (dir.charAt(0) == '/') {
if (dir.length() == 1)
return true;
dir = dir.substring(1);
}
if (dir.length() > 0 && dir.charAt(dir.length() - 1) != '/')
dir = dir + '/';
Enumeration entries = zipFile.entries();
ZipEntry zipEntry;
String entryPath;
while (entries.hasMoreElements()) {
zipEntry = (ZipEntry) entries.nextElement();
entryPath = zipEntry.getName();
if (entryPath.startsWith(dir)) {
return true;
}
}
return false;
}
public synchronized BundleEntry getEntry(String path) {
if (!checkedOpen())
return null;
ZipEntry zipEntry = getZipEntry(path);
if (zipEntry == null) {
if (path.length() == 0 || path.charAt(path.length() - 1) == '/') {
// this is a directory request lets see if any entries exist in this directory
if (containsDir(path))
return new DirZipBundleEntry(this, path);
}
return null;
}
return new ZipBundleEntry(zipEntry, this);
}
public synchronized Enumeration getEntryPaths(String path) {
if (!checkedOpen())
return null;
if (path == null)
throw new NullPointerException();
if (path.length() > 0 && path.charAt(0) == '/')
path = path.substring(1);
if (path.length() > 0 && path.charAt(path.length() - 1) != '/')
path = new StringBuffer(path).append("/").toString(); //$NON-NLS-1$
Vector vEntries = new Vector();
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = (ZipEntry) entries.nextElement();
String entryPath = zipEntry.getName();
if (entryPath.startsWith(path)) {
if (path.length() < entryPath.length()) {
if (entryPath.lastIndexOf('/') < path.length()) {
vEntries.add(entryPath);
} else {
entryPath = entryPath.substring(path.length());
int slash = entryPath.indexOf('/');
entryPath = path + entryPath.substring(0, slash + 1);
if (!vEntries.contains(entryPath))
vEntries.add(entryPath);
}
}
}
}
return vEntries.size() == 0 ? null : vEntries.elements();
}
public synchronized void close() throws IOException {
if (!closed) {
closed = true;
zipFile.close();
mruList.remove(this);
}
}
public void open() throws IOException {
//do nothing
}
/**
* Shutsdown the bundle file closer thread for zip bundle files
*/
public static void shutdown() {
mruList.shutdown();
}
}