package org.eclipse.jdt.internal.core.search.indexing;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipError;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.internal.compiler.env.AutomaticModuleNaming;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.compiler.util.Util;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.index.Index;
import org.eclipse.jdt.internal.core.index.IndexLocation;
import org.eclipse.jdt.internal.core.search.JavaSearchDocument;
import org.eclipse.jdt.internal.core.search.processing.JobManager;
@SuppressWarnings("rawtypes")
class AddJarFileToIndex extends BinaryContainer {
private static final char JAR_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.charAt(0);
IFile resource;
private IndexLocation indexFileURL;
private final boolean forceIndexUpdate;
public AddJarFileToIndex(IFile resource, IndexLocation indexFile, IndexManager manager) {
this(resource, indexFile, manager, false);
}
public AddJarFileToIndex(IFile resource, IndexLocation indexFile, IndexManager manager, final boolean updateIndex) {
super(resource.getFullPath(), manager);
this.resource = resource;
this.indexFileURL = indexFile;
this.forceIndexUpdate = updateIndex;
}
public AddJarFileToIndex(IPath jarPath, IndexLocation indexFile, IndexManager manager) {
this(jarPath, indexFile, manager, false);
}
public AddJarFileToIndex(IPath jarPath, IndexLocation indexFile, IndexManager manager, final boolean updateIndex) {
super(jarPath, manager);
this.indexFileURL = indexFile;
this.forceIndexUpdate = updateIndex;
}
@Override
public boolean equals(Object o) {
if (o instanceof AddJarFileToIndex) {
if (this.resource != null)
return this.resource.equals(((AddJarFileToIndex) o).resource);
if (this.containerPath != null)
return this.containerPath.equals(((AddJarFileToIndex) o).containerPath);
}
return false;
}
@Override
public int hashCode() {
if (this.resource != null)
return this.resource.hashCode();
if (this.containerPath != null)
return this.containerPath.hashCode();
return -1;
}
@Override
public boolean execute(IProgressMonitor progressMonitor) {
if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
if (hasPreBuiltIndex()) {
boolean added = this.manager.addIndex(this.containerPath, this.indexFileURL);
if (added) return true;
this.indexFileURL = null;
}
try {
Index index = this.manager.getIndexForUpdate(this.containerPath, false, false );
if (index != null) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index already exists) for " + this.containerPath);
return true;
}
index = this.manager.getIndexForUpdate(this.containerPath, true, true );
if (index == null) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> index could not be created for " + this.containerPath);
return true;
}
ReadWriteMonitor monitor = index.monitor;
if (monitor == null) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> index for " + this.containerPath + " just got deleted");
return true;
}
index.separator = JAR_SEPARATOR;
ZipFile zip = null;
try {
Path zipFilePath = null;
monitor.enterWrite();
if (this.resource != null) {
URI location = this.resource.getLocationURI();
if (location == null) return false;
if (JavaModelManager.ZIP_ACCESS_VERBOSE)
System.out.println("(" + Thread.currentThread() + ") [AddJarFileToIndex.execute()] Creating ZipFile on " + location.getPath());
File file = null;
try {
file = org.eclipse.jdt.internal.core.util.Util.toLocalFile(location, progressMonitor);
} catch (CoreException e) {
if (JobManager.VERBOSE) {
org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + location.getPath() + " because of the following exception:");
e.printStackTrace();
}
}
if (file == null) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + location.getPath() + " because the file could not be fetched");
return false;
}
if (JavaModelManager.ZIP_ACCESS_VERBOSE)
System.out.println("(" + Thread.currentThread() + ") [AddJarFileToIndex.execute()] Creating ZipFile on " + this.containerPath);
zip = new ZipFile(file);
zipFilePath = (Path) this.resource.getFullPath().makeRelative();
} else {
if (JavaModelManager.ZIP_ACCESS_VERBOSE)
System.out.println("(" + Thread.currentThread() + ") [AddJarFileToIndex.execute()] Creating ZipFile on " + this.containerPath);
zip = new ZipFile(this.containerPath.toFile());
zipFilePath = (Path) this.containerPath;
}
if (this.isCancelled) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing of " + zip.getName() + " has been cancelled");
return false;
}
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing " + zip.getName());
long initialTime = System.currentTimeMillis();
String[] paths = index.queryDocumentNames("");
if (paths != null) {
int max = paths.length;
String EXISTS = "OK";
String DELETED = "DELETED";
SimpleLookupTable indexedFileNames = new SimpleLookupTable(max == 0 ? 33 : max + 11);
for (int i = 0; i < max; i++)
indexedFileNames.put(paths[i], DELETED);
for (Enumeration e = zip.entries(); e.hasMoreElements();) {
ZipEntry ze = (ZipEntry) e.nextElement();
String zipEntryName = ze.getName();
if (Util.isClassFileName(zipEntryName) && isValidPackageNameForClassOrisModule(zipEntryName))
indexedFileNames.put(zipEntryName, EXISTS);
}
boolean needToReindex = indexedFileNames.elementSize != max;
if (!needToReindex) {
Object[] valueTable = indexedFileNames.valueTable;
for (int i = 0, l = valueTable.length; i < l; i++) {
if (valueTable[i] == DELETED) {
needToReindex = true;
break;
}
}
if (!needToReindex) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> no indexing required (index is consistent with library) for "
+ zip.getName() + " ("
+ (System.currentTimeMillis() - initialTime) + "ms)");
this.manager.saveIndex(index);
return true;
}
}
}
SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
if (!this.manager.resetIndex(this.containerPath)) {
this.manager.removeIndex(this.containerPath);
return false;
}
index.separator = JAR_SEPARATOR;
IPath indexPath = null;
IndexLocation indexLocation;
if ((indexLocation = index.getIndexLocation()) != null) {
indexPath = new Path(indexLocation.getCanonicalFilePath());
}
boolean hasModuleInfoClass = false;
for (Enumeration e = zip.entries(); e.hasMoreElements();) {
if (this.isCancelled) {
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> indexing of " + zip.getName() + " has been cancelled");
return false;
}
ZipEntry ze = (ZipEntry) e.nextElement();
String zipEntryName = ze.getName();
if (Util.isClassFileName(zipEntryName) &&
isValidPackageNameForClassOrisModule(zipEntryName)) {
hasModuleInfoClass |= zipEntryName.contains(TypeConstants.MODULE_INFO_NAME_STRING);
final byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getZipEntryByteContent(ze, zip);
JavaSearchDocument entryDocument = new JavaSearchDocument(ze, zipFilePath, classFileBytes, participant);
this.manager.indexDocument(entryDocument, participant, index, indexPath);
}
}
if (!hasModuleInfoClass) {
String s;
try {
s = this.resource == null ? this.containerPath.toOSString() :
JavaModelManager.getLocalFile(this.resource.getFullPath()).toPath().toAbsolutePath().toString();
char[] autoModuleName = AutomaticModuleNaming.determineAutomaticModuleName(s);
final char[] contents = CharOperation.append(CharOperation.append(TypeConstants.AUTOMATIC_MODULE_NAME.toCharArray(), ':'), autoModuleName);
ZipEntry ze = new ZipEntry(TypeConstants.AUTOMATIC_MODULE_NAME);
JavaSearchDocument entryDocument = new JavaSearchDocument(ze, zipFilePath, new String(contents).getBytes(Charset.defaultCharset()), participant);
this.manager.indexDocument(entryDocument, participant, index, indexPath);
} catch (CoreException e) {
}
}
if(this.forceIndexUpdate) {
this.manager.savePreBuiltIndex(index);
}
else {
this.manager.saveIndex(index);
}
if (JobManager.VERBOSE)
org.eclipse.jdt.internal.core.util.Util.verbose("-> done indexing of "
+ zip.getName() + " ("
+ (System.currentTimeMillis() - initialTime) + "ms)");
} finally {
if (zip != null) {
if (JavaModelManager.ZIP_ACCESS_VERBOSE)
System.out.println("(" + Thread.currentThread() + ") [AddJarFileToIndex.execute()] Closing ZipFile " + this.containerPath);
zip.close();
}
monitor.exitWrite();
}
} catch (IOException | ZipError e) {
if (JobManager.VERBOSE) {
org.eclipse.jdt.internal.core.util.Util.verbose("-> failed to index " + this.containerPath + " because of the following exception:");
e.printStackTrace();
}
this.manager.removeIndex(this.containerPath);
return false;
}
return true;
}
@Override
public String getJobFamily() {
if (this.resource != null)
return super.getJobFamily();
return this.containerPath.toOSString();
}
@Override
protected Integer updatedIndexState() {
Integer updateState = null;
if(hasPreBuiltIndex()) {
updateState = IndexManager.REUSE_STATE;
}
else {
updateState = IndexManager.REBUILDING_STATE;
}
return updateState;
}
@Override
public String toString() {
return "indexing " + this.containerPath.toString();
}
protected boolean hasPreBuiltIndex() {
return !this.forceIndexUpdate && (this.indexFileURL != null && this.indexFileURL.exists());
}
}