blob: ba3817b0f541dda71557732ee6cec96038730ad4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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
* Tal Lev-Ami - added package cache for zip files
*******************************************************************************/
package org.eclipse.jdt.internal.core.builder;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.core.util.SimpleSet;
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class ClasspathJar extends ClasspathLocation {
static class PackageCacheEntry {
long lastModified;
long fileSize;
SimpleSet packageSet;
PackageCacheEntry(long lastModified, long fileSize, SimpleSet packageSet) {
this.lastModified = lastModified;
this.fileSize = fileSize;
this.packageSet = packageSet;
}
}
static SimpleLookupTable PackageCache = new SimpleLookupTable();
/**
* Calculate and cache the package list available in the zipFile.
* @param zipFile The zip file to use
* @return A SimpleSet with the all the package names in the zipFile.
*/
static SimpleSet findPackageSet(ZipFile zipFile) {
String zipFileName = zipFile.getName();
File zipFileObject = new File(zipFileName);
long lastModified = zipFileObject.lastModified();
long fileSize = zipFileObject.length();
PackageCacheEntry cacheEntry = (PackageCacheEntry) PackageCache.get(zipFileName);
if (cacheEntry != null && cacheEntry.lastModified == lastModified && cacheEntry.fileSize == fileSize)
return cacheEntry.packageSet;
SimpleSet packageSet = new SimpleSet(41);
packageSet.add(""); //$NON-NLS-1$
nextEntry : for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) {
String fileName = ((ZipEntry) e.nextElement()).getName();
// add the package name & all of its parent packages
int last = fileName.lastIndexOf('/');
while (last > 0) {
// extract the package name
String packageName = fileName.substring(0, last);
if (packageSet.includes(packageName))
continue nextEntry;
packageSet.add(packageName);
last = packageName.lastIndexOf('/');
}
}
PackageCache.put(zipFileName, new PackageCacheEntry(lastModified, fileSize, packageSet));
return packageSet;
}
String zipFilename; // keep for equals
IFile resource;
ZipFile zipFile;
boolean closeZipFileAtEnd;
SimpleSet knownPackageNames;
AccessRuleSet accessRuleSet;
ClasspathJar(String zipFilename, AccessRuleSet accessRuleSet) {
this.zipFilename = zipFilename;
this.zipFile = null;
this.knownPackageNames = null;
this.accessRuleSet = accessRuleSet;
}
ClasspathJar(IFile resource, AccessRuleSet accessRuleSet) {
this.resource = resource;
IPath location = resource.getLocation();
this.zipFilename = location != null ? location.toString() : ""; //$NON-NLS-1$
this.zipFile = null;
this.knownPackageNames = null;
this.accessRuleSet = accessRuleSet;
}
public ClasspathJar(ZipFile zipFile, AccessRuleSet accessRuleSet) {
this.zipFilename = zipFile.getName();
this.zipFile = zipFile;
this.closeZipFileAtEnd = false;
this.knownPackageNames = null;
this.accessRuleSet = accessRuleSet;
}
public void cleanup() {
if (this.zipFile != null && this.closeZipFileAtEnd) {
try {
this.zipFile.close();
} catch(IOException e) { // ignore it
}
this.zipFile = null;
}
this.knownPackageNames = null;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClasspathJar)) return false;
ClasspathJar jar = (ClasspathJar) o;
if (this.accessRuleSet != jar.accessRuleSet)
if (this.accessRuleSet == null || !this.accessRuleSet.equals(jar.accessRuleSet))
return false;
return this.zipFilename.equals(((ClasspathJar) o).zipFilename);
}
public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String qualifiedBinaryFileName) {
if (!isPackage(qualifiedPackageName)) return null; // most common case
try {
ClassFileReader reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName);
if (reader != null) {
if (this.accessRuleSet == null)
return new NameEnvironmentAnswer(reader, null);
return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(qualifiedBinaryFileName.toCharArray()));
}
} catch (Exception e) { // treat as if class file is missing
}
return null;
}
public IPath getProjectRelativePath() {
if (this.resource == null) return null;
return this.resource.getProjectRelativePath();
}
public boolean isPackage(String qualifiedPackageName) {
if (this.knownPackageNames != null)
return this.knownPackageNames.includes(qualifiedPackageName);
try {
if (this.zipFile == null) {
if (org.eclipse.jdt.internal.core.JavaModelManager.ZIP_ACCESS_VERBOSE) {
System.out.println("(" + Thread.currentThread() + ") [ClasspathJar.isPackage(String)] Creating ZipFile on " + zipFilename); //$NON-NLS-1$ //$NON-NLS-2$
}
this.zipFile = new ZipFile(zipFilename);
this.closeZipFileAtEnd = true;
}
this.knownPackageNames = findPackageSet(this.zipFile);
} catch(Exception e) {
this.knownPackageNames = new SimpleSet(); // assume for this build the zipFile is empty
}
return this.knownPackageNames.includes(qualifiedPackageName);
}
public String toString() {
String start = "Classpath jar file " + this.zipFilename; //$NON-NLS-1$
if (this.accessRuleSet == null)
return start;
return start + " with " + this.accessRuleSet; //$NON-NLS-1$
}
}