001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Tal Lev-Ami - added package cache for zip files
011: *******************************************************************************/package org.eclipse.jdt.internal.core.builder;
012:
013: import org.eclipse.core.resources.IFile;
014: import org.eclipse.core.runtime.*;
015:
016: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
017: import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
018: import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
019: import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
020: import org.eclipse.jdt.internal.compiler.util.SimpleSet;
021: import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
022: import org.eclipse.jdt.internal.core.util.Util;
023:
024: import java.io.*;
025: import java.util.*;
026: import java.util.zip.*;
027:
028: public class ClasspathJar extends ClasspathLocation {
029:
030: static class PackageCacheEntry {
031: long lastModified;
032: long fileSize;
033: SimpleSet packageSet;
034:
035: PackageCacheEntry(long lastModified, long fileSize,
036: SimpleSet packageSet) {
037: this .lastModified = lastModified;
038: this .fileSize = fileSize;
039: this .packageSet = packageSet;
040: }
041: }
042:
043: static SimpleLookupTable PackageCache = new SimpleLookupTable();
044:
045: /**
046: * Calculate and cache the package list available in the zipFile.
047: * @param jar The ClasspathJar to use
048: * @return A SimpleSet with the all the package names in the zipFile.
049: */
050: static SimpleSet findPackageSet(ClasspathJar jar) {
051: String zipFileName = jar.zipFilename;
052: long lastModified = jar.lastModified();
053: long fileSize = new File(zipFileName).length();
054: PackageCacheEntry cacheEntry = (PackageCacheEntry) PackageCache
055: .get(zipFileName);
056: if (cacheEntry != null
057: && cacheEntry.lastModified == lastModified
058: && cacheEntry.fileSize == fileSize)
059: return cacheEntry.packageSet;
060:
061: SimpleSet packageSet = new SimpleSet(41);
062: packageSet.add(""); //$NON-NLS-1$
063: nextEntry: for (Enumeration e = jar.zipFile.entries(); e
064: .hasMoreElements();) {
065: String fileName = ((ZipEntry) e.nextElement()).getName();
066:
067: // add the package name & all of its parent packages
068: int last = fileName.lastIndexOf('/');
069: while (last > 0) {
070: // extract the package name
071: String packageName = fileName.substring(0, last);
072: if (packageSet.addIfNotIncluded(packageName) == null)
073: continue nextEntry; // already existed
074: last = packageName.lastIndexOf('/');
075: }
076: }
077:
078: PackageCache.put(zipFileName, new PackageCacheEntry(
079: lastModified, fileSize, packageSet));
080: return packageSet;
081: }
082:
083: String zipFilename; // keep for equals
084: IFile resource;
085: ZipFile zipFile;
086: long lastModified;
087: boolean closeZipFileAtEnd;
088: SimpleSet knownPackageNames;
089: AccessRuleSet accessRuleSet;
090:
091: ClasspathJar(IFile resource, AccessRuleSet accessRuleSet) {
092: this .resource = resource;
093: try {
094: java.net.URI location = resource.getLocationURI();
095: if (location == null) {
096: this .zipFilename = ""; //$NON-NLS-1$
097: } else {
098: File localFile = Util.toLocalFile(location, null);
099: this .zipFilename = localFile.getPath();
100: }
101: } catch (CoreException e) {
102: // ignore
103: }
104: this .zipFile = null;
105: this .knownPackageNames = null;
106: this .accessRuleSet = accessRuleSet;
107: }
108:
109: ClasspathJar(String zipFilename, long lastModified,
110: AccessRuleSet accessRuleSet) {
111: this .zipFilename = zipFilename;
112: this .lastModified = lastModified;
113: this .zipFile = null;
114: this .knownPackageNames = null;
115: this .accessRuleSet = accessRuleSet;
116: }
117:
118: public ClasspathJar(ZipFile zipFile, AccessRuleSet accessRuleSet) {
119: this .zipFilename = zipFile.getName();
120: this .zipFile = zipFile;
121: this .closeZipFileAtEnd = false;
122: this .knownPackageNames = null;
123: this .accessRuleSet = accessRuleSet;
124: }
125:
126: public void cleanup() {
127: if (this .zipFile != null && this .closeZipFileAtEnd) {
128: try {
129: this .zipFile.close();
130: } catch (IOException e) { // ignore it
131: }
132: this .zipFile = null;
133: }
134: this .knownPackageNames = null;
135: }
136:
137: public boolean equals(Object o) {
138: if (this == o)
139: return true;
140: if (!(o instanceof ClasspathJar))
141: return false;
142:
143: ClasspathJar jar = (ClasspathJar) o;
144: if (this .accessRuleSet != jar.accessRuleSet)
145: if (this .accessRuleSet == null
146: || !this .accessRuleSet.equals(jar.accessRuleSet))
147: return false;
148: return this .zipFilename.equals(jar.zipFilename)
149: && this .lastModified() == jar.lastModified();
150: }
151:
152: public NameEnvironmentAnswer findClass(String binaryFileName,
153: String qualifiedPackageName, String qualifiedBinaryFileName) {
154: if (!isPackage(qualifiedPackageName))
155: return null; // most common case
156:
157: try {
158: ClassFileReader reader = ClassFileReader.read(this .zipFile,
159: qualifiedBinaryFileName);
160: if (reader != null) {
161: if (this .accessRuleSet == null)
162: return new NameEnvironmentAnswer(reader, null);
163: String fileNameWithoutExtension = qualifiedBinaryFileName
164: .substring(0, qualifiedBinaryFileName.length()
165: - SuffixConstants.SUFFIX_CLASS.length);
166: return new NameEnvironmentAnswer(
167: reader,
168: this .accessRuleSet
169: .getViolatedRestriction(fileNameWithoutExtension
170: .toCharArray()));
171: }
172: } catch (Exception e) { // treat as if class file is missing
173: }
174: return null;
175: }
176:
177: public IPath getProjectRelativePath() {
178: if (this .resource == null)
179: return null;
180: return this .resource.getProjectRelativePath();
181: }
182:
183: public boolean isPackage(String qualifiedPackageName) {
184: if (this .knownPackageNames != null)
185: return this .knownPackageNames
186: .includes(qualifiedPackageName);
187:
188: try {
189: if (this .zipFile == null) {
190: if (org.eclipse.jdt.internal.core.JavaModelManager.ZIP_ACCESS_VERBOSE) {
191: System.out
192: .println("(" + Thread.currentThread() + ") [ClasspathJar.isPackage(String)] Creating ZipFile on " + zipFilename); //$NON-NLS-1$ //$NON-NLS-2$
193: }
194: this .zipFile = new ZipFile(zipFilename);
195: this .closeZipFileAtEnd = true;
196: }
197: this .knownPackageNames = findPackageSet(this );
198: } catch (Exception e) {
199: this .knownPackageNames = new SimpleSet(); // assume for this build the zipFile is empty
200: }
201: return this .knownPackageNames.includes(qualifiedPackageName);
202: }
203:
204: public long lastModified() {
205: if (this .lastModified == 0)
206: this .lastModified = new File(this .zipFilename)
207: .lastModified();
208: return this .lastModified;
209: }
210:
211: public String toString() {
212: String start = "Classpath jar file " + this .zipFilename; //$NON-NLS-1$
213: if (this .accessRuleSet == null)
214: return start;
215: return start + " with " + this .accessRuleSet; //$NON-NLS-1$
216: }
217:
218: public String debugPathString() {
219: long time = lastModified();
220: if (time == 0)
221: return this .zipFilename;
222: return this .zipFilename + '(' + (new Date(time))
223: + " : " + time + ')'; //$NON-NLS-1$
224: }
225:
226: }
|