/******************************************************************************* * 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$ } }