/*******************************************************************************
* Copyright (c) 2004, 2012 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.che.jdt.internal.core.builder;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.internal.codeassist.ISearchRequestor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ClasspathJar extends CodenvyClasspathLocation {
// static SimpleLookupTable PackageCache = new SimpleLookupTable();
String zipFilename; // keep for equals
IFile resource;
ZipFile zipFile;
long lastModified;
boolean closeZipFileAtEnd;
volatile SimpleSet knownPackageNames;
AccessRuleSet accessRuleSet;
Set<String[]> packageNames;
ClasspathJar(IFile resource, AccessRuleSet accessRuleSet) {
this.resource = resource;
try {
java.net.URI location = resource.getLocationURI();
if (location == null) {
this.zipFilename = ""; //$NON-NLS-1$
} else {
File localFile = Util.toLocalFile(location, null);
this.zipFilename = localFile.getPath();
}
} catch (CoreException e) {
// ignore
}
this.zipFile = null;
this.knownPackageNames = null;
packageNames = null;
this.accessRuleSet = accessRuleSet;
}
ClasspathJar(String zipFilename, long lastModified, AccessRuleSet accessRuleSet) {
this.zipFilename = zipFilename;
this.lastModified = lastModified;
this.zipFile = null;
this.knownPackageNames = null;
this.accessRuleSet = accessRuleSet;
}
public ClasspathJar(ZipFile zipFile, AccessRuleSet accessRuleSet) {
this.zipFilename = zipFile.getName();
this.zipFile = zipFile;
this.closeZipFileAtEnd = true;
this.knownPackageNames = null;
this.accessRuleSet = accessRuleSet;
}
/**
* Calculate and cache the package list available in the zipFile.
*
* @param jar
* The ClasspathJar to use
* @return A SimpleSet with the all the package names in the zipFile.
*/
static SimpleSet findPackageSet(ClasspathJar jar) {
String zipFileName = jar.zipFilename;
SimpleSet packageSet = new SimpleSet(41);
packageSet.add(""); //$NON-NLS-1$
nextEntry:
for (Enumeration e = jar.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);
String[] splittedName = Util.splitOn('/', packageName, 0, packageName.length());
for (String s : splittedName) {
if (!org.eclipse.jdt.internal.core.util.Util.isValidFolderNameForPackage(s, "1.7", "1.7")) {
continue nextEntry;
}
}
if (packageSet.addIfNotIncluded(packageName) == null)
continue nextEntry; // already existed
last = packageName.lastIndexOf('/');
}
}
return packageSet;
}
@Override
public void findPackages(String[] name, ISearchRequestor requestor) {
SimpleSet knownPackageNames = getKnownPackages();
for (Object value : knownPackageNames.values) {
if (value == null) {
continue;
}
String pkg = value.toString();
String[] pkgName = Util.splitOn('/', pkg, 0, pkg.length());
if (pkgName != null && Util.startsWithIgnoreCase(pkgName, name, true)) {
requestor.acceptPackage(Util.concatWith(pkgName, '.').toCharArray());
}
}
}
private SimpleSet getKnownPackages() {
SimpleSet packageNames = knownPackageNames;
if (packageNames == null) {
synchronized (this){
packageNames = knownPackageNames;
if(packageNames == null){
packageNames = readPackages();
knownPackageNames = packageNames;
}
}
}
return packageNames;
}
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(jar.zipFilename) && lastModified() == jar.lastModified();
}
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);
String fileNameWithoutExtension =
qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length);
return new NameEnvironmentAnswer(reader, this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()));
}
} catch (IOException | ClassFormatException e) { // treat as if class file is missing
}
return null;
}
public IPath getProjectRelativePath() {
if (this.resource == null) return null;
return this.resource.getProjectRelativePath();
}
public int hashCode() {
return this.zipFilename == null ? super.hashCode() : this.zipFilename.hashCode();
}
public boolean isPackage(String qualifiedPackageName) {
SimpleSet knownPackages = getKnownPackages();
return knownPackages.includes(qualifiedPackageName);
}
private SimpleSet readPackages() {
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 " +
this.zipFilename
); //$NON-NLS-1$ //$NON-NLS-2$
}
this.zipFile = new ZipFile(this.zipFilename);
this.closeZipFileAtEnd = true;
}
return findPackageSet(this);
} catch (Exception e) {
return new SimpleSet(); // assume for this build the zipFile is empty
}
}
public long lastModified() {
if (this.lastModified == 0)
this.lastModified = new File(this.zipFilename).lastModified();
return this.lastModified;
}
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$
}
public String debugPathString() {
long time = lastModified();
if (time == 0)
return this.zipFilename;
return this.zipFilename + '(' + (new Date(time)) + " : " + time + ')'; //$NON-NLS-1$
}
}