package org.rubypeople.rdt.internal.core.search.indexing;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.rubypeople.rdt.core.search.SearchParticipant;
import org.rubypeople.rdt.internal.compiler.util.SimpleLookupTable;
import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.core.index.Index;
import org.rubypeople.rdt.internal.core.search.BasicSearchEngine;
import org.rubypeople.rdt.internal.core.search.ERBSearchDocument;
import org.rubypeople.rdt.internal.core.search.RubySearchDocument;
import org.rubypeople.rdt.internal.core.search.processing.JobManager;
import org.rubypeople.rdt.internal.core.util.Util;
public class AddExternalFolderToIndex extends IndexRequest {
public AddExternalFolderToIndex(IPath containerPath, IndexManager manager) {
super(containerPath, manager);
}
public boolean execute(IProgressMonitor progressMonitor) {
if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled())
return true;
try {
// if index is already cached, then do not perform any check
// MUST reset the IndexManager if a jar file is changed
Index index = this.manager.getIndexForUpdate(this.containerPath, false, /* do not reuse index file */false /* do not create if none */);
if (index != null) {
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> no indexing required (index already exists) for " + this.containerPath); //$NON-NLS-1$
return true;
}
index = this.manager.getIndexForUpdate(this.containerPath, true, /* reuse index file */true /* create if none */);
if (index == null) {
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> index could not be created for " + this.containerPath); //$NON-NLS-1$
return true;
}
ReadWriteMonitor monitor = index.monitor;
if (monitor == null) {
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> index for " + this.containerPath + " just got deleted"); //$NON-NLS-1$//$NON-NLS-2$
return true; // index got deleted since acquired
}
File file = null;
try {
monitor.enterWrite(); // ask permission to write
if (RubyModelManager.ZIP_ACCESS_VERBOSE)
System.out.println("(" + Thread.currentThread() + ") [AddJarFileToIndex.execute()] Creating ZipFile on " + this.containerPath); //$NON-NLS-1$ //$NON-NLS-2$
// external file -> it is ok to use toFile()
file = this.containerPath.toFile();
// path is already canonical since coming from a library
// classpath entry
if (this.isCancelled) {
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> indexing of " + file.getName() + " has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> indexing " + file.getName()); //$NON-NLS-1$
long initialTime = System.currentTimeMillis();
String[] paths = index.queryDocumentNames(""); // all file
// names
// //$NON-NLS-1$
if (paths != null) {
int max = paths.length;
/*
* check integrity of the existing index file if the length
* is equal to 0, we want to index the whole jar again If
* not, then we want to check that there is no missing
* entry, if one entry is missing then we recreate the index
*/
String EXISTS = "OK"; //$NON-NLS-1$
String DELETED = "DELETED"; //$NON-NLS-1$
SimpleLookupTable indexedFileNames = new SimpleLookupTable(max == 0 ? 33 : max + 11);
for (int i = 0; i < max; i++)
indexedFileNames.put(paths[i], DELETED);
addDirectorysChildren(file, EXISTS, indexedFileNames);
boolean needToReindex = indexedFileNames.elementSize != max; // a
// new
// file
// was
// added
if (!needToReindex) {
Object[] valueTable = indexedFileNames.valueTable;
for (int i = 0, l = valueTable.length; i < l; i++) {
if (valueTable[i] == DELETED) {
needToReindex = true; // a file was deleted so
// re-index
break;
}
}
if (!needToReindex) {
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> no indexing required (index is consistent with library) for " //$NON-NLS-1$
+ file.getName() + " (" //$NON-NLS-1$
+ (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$
this.manager.saveIndex(index); // to ensure its
// placed into the
// saved state
return true;
}
}
}
// Index the jar for the first time or reindex the jar in case
// the previous index file has been corrupted
// index already existed: recreate it so that we forget about
// previous entries
SearchParticipant participant = BasicSearchEngine.getDefaultSearchParticipant();
index = manager.recreateIndex(this.containerPath);
if (index == null) {
// failed to recreate index, see 73330
manager.removeIndex(this.containerPath);
return false;
}
if (!indexFiles(index, file, participant)) return false;
this.manager.saveIndex(index);
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> done indexing of " //$NON-NLS-1$
+ file.getName() + " (" //$NON-NLS-1$
+ (System.currentTimeMillis() - initialTime) + "ms)"); //$NON-NLS-1$
} finally {
monitor.exitWrite(); // free write lock
}
} catch (IOException e) {
if (JobManager.VERBOSE) {
org.rubypeople.rdt.internal.core.util.Util.verbose("-> failed to index " + this.containerPath + " because of the following exception:"); //$NON-NLS-1$ //$NON-NLS-2$
e.printStackTrace();
}
manager.removeIndex(this.containerPath);
return false;
}
return true;
}
private boolean indexFiles(Index index, File file, SearchParticipant participant) throws FileNotFoundException, IOException {
File[] children = file.listFiles();
if (children == null) return true;
for (int i = 0; i < children.length; i++) {
if (this.isCancelled) {
if (JobManager.VERBOSE)
org.rubypeople.rdt.internal.core.util.Util.verbose("-> indexing of " + file.getName() + " has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
String name = children[i].getName();
if (children[i].isFile() && Util.isRubyOrERBLikeFileName(name)) {
InputStream stream = new FileInputStream(children[i]);
char[] contents = Util.getInputStreamAsCharArray(stream, -1, null);
RubySearchDocument entryDocument;
if (Util.isERBLikeFileName(name)) {
entryDocument = new ERBSearchDocument(children[i].getAbsolutePath(), contents, participant);
} else {
entryDocument = new RubySearchDocument(children[i].getAbsolutePath(), contents, participant);
}
this.manager.indexDocument(entryDocument, participant, index, this.containerPath);
}
if (!indexFiles(index, children[i], participant)) return false;
}
return true;
}
private void addDirectorysChildren(File file, String EXISTS, SimpleLookupTable indexedFileNames) {
File[] children = file.listFiles();
if (children == null) return;
for (int i = 0; i < children.length; i++) {
String name = children[i].getName();
if (Util.isRubyOrERBLikeFileName(name)) {
indexedFileNames.put(name, EXISTS);
}
addDirectorysChildren(children[i], EXISTS, indexedFileNames);
}
}
protected Integer updatedIndexState() {
return IndexManager.REBUILDING_STATE;
}
public String toString() {
return "indexing " + this.containerPath.toString(); //$NON-NLS-1$
}
public boolean equals(Object o) {
if (o instanceof AddExternalFolderToIndex) {
if (this.containerPath != null)
return this.containerPath.equals(((AddExternalFolderToIndex) o).containerPath);
}
return false;
}
public int hashCode() {
if (this.containerPath != null)
return this.containerPath.hashCode();
return -1;
}
}