package org.eclipse.jdt.internal.core.search.indexing;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import java.util.zip.CRC32;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchDocument;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
import org.eclipse.jdt.internal.compiler.SourceElementParser;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.util.JRTUtil;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.core.ClasspathEntry;
import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.index.DiskIndex;
import org.eclipse.jdt.internal.core.index.FileIndexLocation;
import org.eclipse.jdt.internal.core.index.Index;
import org.eclipse.jdt.internal.core.index.IndexLocation;
import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
import org.eclipse.jdt.internal.core.search.PatternSearchJob;
import org.eclipse.jdt.internal.core.search.processing.IJob;
import org.eclipse.jdt.internal.core.search.processing.JobManager;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
@SuppressWarnings({"rawtypes", "unchecked"})
public class IndexManager extends JobManager implements IIndexConstants {
public SimpleLookupTable indexLocations = new SimpleLookupTable();
private SimpleLookupTable indexes = new SimpleLookupTable();
private boolean needToSave = false;
private IPath javaPluginLocation = null;
private SimpleLookupTable indexStates = null;
private File indexNamesMapFile = new File(getSavedIndexesDirectory(), "indexNamesMap.txt");
private File participantIndexNamesFile = new File(getSavedIndexesDirectory(), "participantsIndexNames.txt");
private boolean javaLikeNamesChanged = true;
public static final Integer SAVED_STATE = 0;
public static final Integer UPDATING_STATE = 1;
public static final Integer UNKNOWN_STATE = 2;
public static final Integer REBUILDING_STATE = 3;
public static final Integer REUSE_STATE = 4;
private final IndexNamesRegistry nameRegistry = new IndexNamesRegistry(new File(getSavedIndexesDirectory(),
"savedIndexNames.txt"), getJavaPluginWorkingLocation());
private SimpleLookupTable participantsContainers = null;
private boolean participantUpdated = false;
public static final String MANAGE_PRODUCT_INDEXES_PROPERTY = "jdt.core.manageProductIndexes";
private static final boolean IS_MANAGING_PRODUCT_INDEXES_PROPERTY = Boolean.getBoolean(MANAGE_PRODUCT_INDEXES_PROPERTY);
public static boolean DEBUG = false;
public synchronized void aboutToUpdateIndex(IPath containerPath, Integer newIndexState) {
IndexLocation indexLocation = computeIndexLocation(containerPath);
Object state = getIndexStates().get(indexLocation);
Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state;
if (currentIndexState.compareTo(REBUILDING_STATE) >= 0) return;
int compare = newIndexState.compareTo(currentIndexState);
if (compare > 0) {
updateIndexState(indexLocation, newIndexState);
} else if (compare < 0 && this.indexes.get(indexLocation) == null) {
rebuildIndex(indexLocation, containerPath);
}
}
public void addBinary(IFile resource, IPath containerPath) {
if (JavaCore.getPlugin() == null) return;
SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
SearchDocument document = participant.getDocument(resource.getFullPath().toString());
IndexLocation indexLocation = computeIndexLocation(containerPath);
scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
}
public void addSource(IFile resource, IPath containerPath, SourceElementParser parser) {
if (JavaCore.getPlugin() == null) return;
SearchParticipant participant = SearchEngine.getDefaultSearchParticipant();
SearchDocument document = participant.getDocument(resource.getFullPath().toString());
document.setParser(parser);
IndexLocation indexLocation = computeIndexLocation(containerPath);
scheduleDocumentIndexing(document, containerPath, indexLocation, participant);
}
public void cleanUpIndexes() {
SimpleSet knownPaths = new SimpleSet();
IJavaSearchScope scope = BasicSearchEngine.createWorkspaceScope();
PatternSearchJob job = new PatternSearchJob(null, SearchEngine.getDefaultSearchParticipant(), scope, null);
Index[] selectedIndexes = job.getIndexes(null);
for (int i = 0, l = selectedIndexes.length; i < l; i++) {
IndexLocation IndexLocation = selectedIndexes[i].getIndexLocation();
knownPaths.add(IndexLocation);
}
if (this.indexStates != null) {
Object[] keys = this.indexStates.keyTable;
IndexLocation[] locations = new IndexLocation[this.indexStates.elementSize];
int count = 0;
for (int i = 0, l = keys.length; i < l; i++) {
IndexLocation key = (IndexLocation) keys[i];
if (key != null && !knownPaths.includes(key))
locations[count++] = key;
}
if (count > 0)
removeIndexesState(locations);
}
deleteIndexFiles(knownPaths, null);
}
public synchronized IndexLocation computeIndexLocation(IPath containerPath, final URL newIndexURL) {
IndexLocation indexLocation = (IndexLocation) this.indexLocations.get(containerPath);
if (indexLocation == null) {
if(newIndexURL != null) {
indexLocation = IndexLocation.createIndexLocation(newIndexURL);
indexLocation = (IndexLocation) getIndexStates().getKey(indexLocation);
this.indexLocations.put(containerPath, indexLocation);
}
}
else {
URL existingURL = indexLocation.getUrl();
if (newIndexURL != null) {
if(!newIndexURL.equals(existingURL)) {
this.removeIndex(containerPath);
indexLocation = IndexLocation.createIndexLocation(newIndexURL);
indexLocation = (IndexLocation) getIndexStates().getKey(indexLocation);
this.indexLocations.put(containerPath, indexLocation);
}
}
}
return indexLocation;
}
public synchronized IndexLocation computeIndexLocation(IPath containerPath) {
IndexLocation indexLocation = (IndexLocation) this.indexLocations.get(containerPath);
if (indexLocation == null) {
String pathString = containerPath.toOSString();
CRC32 checksumCalculator = new CRC32();
checksumCalculator.update(pathString.getBytes());
String fileName = Long.toString(checksumCalculator.getValue()) + ".index";
if (VERBOSE)
Util.verbose("-> index name for " + pathString + " is " + fileName);
indexLocation = (IndexLocation) getIndexStates().getKey(new FileIndexLocation(new File(getSavedIndexesDirectory(), fileName)));
this.indexLocations.put(containerPath, indexLocation);
}
return indexLocation;
}
public final void deleteIndexFiles() {
deleteIndexFiles(null);
}
public void deleteIndexFiles(IProgressMonitor monitor) {
if (DEBUG)
Util.verbose("Deleting index files");
this.nameRegistry.delete();
deleteIndexFiles(null, monitor);
}
private void deleteIndexFiles(SimpleSet pathsToKeep, IProgressMonitor monitor) {
File[] indexesFiles = getSavedIndexesDirectory().listFiles();
if (indexesFiles == null) return;
SubMonitor subMonitor = SubMonitor.convert(monitor, indexesFiles.length);
for (int i = 0, l = indexesFiles.length; i < l; i++) {
subMonitor.split(1);
String fileName = indexesFiles[i].getAbsolutePath();
if (pathsToKeep != null && pathsToKeep.includes(new FileIndexLocation(indexesFiles[i]))) continue;
String suffix = ".index";
if (fileName.regionMatches(true, fileName.length() - suffix.length(), suffix, 0, suffix.length())) {
if (VERBOSE || DEBUG)
Util.verbose("Deleting index file " + indexesFiles[i]);
indexesFiles[i].delete();
}
}
}
public synchronized void ensureIndexExists(IndexLocation indexLocation, IPath containerPath) {
SimpleLookupTable states = getIndexStates();
Object state = states.get(indexLocation);
if (state == null) {
updateIndexState(indexLocation, REBUILDING_STATE);
getIndex(containerPath, indexLocation, true, true);
}
}
public SourceElementParser getSourceElementParser(IJavaProject project, ISourceElementRequestor requestor) {
Map options = project.getOptions(true);
options.put(JavaCore.COMPILER_TASK_TAGS, "");
SourceElementParser parser = new IndexingParser(
requestor,
new DefaultProblemFactory(Locale.getDefault()),
new CompilerOptions(options),
true,
true,
false);
parser.reportOnlyOneSyntaxError = true;
parser.javadocParser.checkDocComment = true;
parser.javadocParser.reportProblems = false;
return parser;
}
public synchronized Index getIndex(IndexLocation indexLocation) {
return (Index) this.indexes.get(indexLocation);
}
public synchronized Index getIndex(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) {
IndexLocation indexLocation = computeIndexLocation(containerPath);
return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing);
}
public synchronized Index getIndex(IPath containerPath, IndexLocation indexLocation, boolean reuseExistingFile, boolean createIfMissing) {
Index index = getIndex(indexLocation);
if (index == null) {
Object state = getIndexStates().get(indexLocation);
Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state;
if (currentIndexState == UNKNOWN_STATE) {
rebuildIndex(indexLocation, containerPath);
return null;
}
String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
if (reuseExistingFile) {
if (indexLocation.exists()) {
try {
index = new Index(indexLocation, containerPathString, true );
this.indexes.put(indexLocation, index);
return index;
} catch (IOException e) {
if (currentIndexState != REBUILDING_STATE && currentIndexState != REUSE_STATE) {
if (VERBOSE)
Util.verbose("-> cannot reuse existing index: "+indexLocation+" path: "+containerPathString);
rebuildIndex(indexLocation, containerPath);
return null;
}
}
}
if (currentIndexState == SAVED_STATE) {
rebuildIndex(indexLocation, containerPath);
return null;
}
if (currentIndexState == REUSE_STATE) {
if (VERBOSE)
Util.verbose("-> cannot reuse given index: "+indexLocation+" path: "+containerPathString);
if(!IS_MANAGING_PRODUCT_INDEXES_PROPERTY) {
this.indexLocations.put(containerPath, null);
indexLocation = computeIndexLocation(containerPath);
rebuildIndex(indexLocation, containerPath);
}
else {
rebuildIndex(indexLocation, containerPath, true);
}
return null;
}
}
if (createIfMissing) {
try {
if (VERBOSE)
Util.verbose("-> create empty index: "+indexLocation+" path: "+containerPathString);
index = new Index(indexLocation, containerPathString, false );
this.indexes.put(indexLocation, index);
return index;
} catch (IOException e) {
if (VERBOSE)
Util.verbose("-> unable to create empty index: "+indexLocation+" path: "+containerPathString);
return null;
}
}
}
return index;
}
public Index[] getIndexes(IndexLocation[] locations, IProgressMonitor progressMonitor) {
int length = locations.length;
Index[] locatedIndexes = new Index[length];
int count = 0;
if (this.javaLikeNamesChanged) {
this.javaLikeNamesChanged = hasJavaLikeNamesChanged();
}
for (int i = 0; i < length; i++) {
if (progressMonitor != null && progressMonitor.isCanceled()) {
throw new OperationCanceledException();
}
IndexLocation indexLocation = locations[i];
Index index = getIndex(indexLocation);
if (index == null) {
IPath containerPath = (IPath) this.indexLocations.keyForValue(indexLocation);
if (containerPath != null) {
index = getIndex(containerPath, indexLocation, true , false );
if (index != null && this.javaLikeNamesChanged && !index.isIndexForJar()) {
File indexFile = index.getIndexFile();
if (indexFile.exists()) {
if (DEBUG)
Util.verbose("Change in javaLikeNames - removing index file for " + containerPath );
indexFile.delete();
}
this.indexes.put(indexLocation, null);
rebuildIndex(indexLocation, containerPath);
index = null;
}
} else {
if (indexLocation.isParticipantIndex() && indexLocation.exists()) {
try {
IPath container = getParticipantsContainer(indexLocation);
if (container != null) {
index = new Index(indexLocation, container.toOSString(), true );
this.indexes.put(indexLocation, index);
}
} catch (IOException e) {
}
}
}
}
if (index != null)
locatedIndexes[count++] = index;
}
if (this.javaLikeNamesChanged) {
writeJavaLikeNamesFile();
this.javaLikeNamesChanged = false;
}
if (count < length) {
System.arraycopy(locatedIndexes, 0, locatedIndexes=new Index[count], 0, count);
}
return locatedIndexes;
}
public synchronized Index getIndexForUpdate(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) {
IndexLocation indexLocation = computeIndexLocation(containerPath);
if (getIndexStates().get(indexLocation) == REBUILDING_STATE)
return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing);
return null;
}
private SimpleLookupTable getIndexStates() {
if (this.indexStates != null) return this.indexStates;
this.indexStates = new SimpleLookupTable();
File indexesDirectoryPath = getSavedIndexesDirectory();
char[][] savedNames = this.nameRegistry.read(null);
if (savedNames != null) {
for (int i = 1, l = savedNames.length; i < l; i++) {
char[] savedName = savedNames[i];
if (savedName.length > 0) {
IndexLocation indexLocation = new FileIndexLocation(new File(indexesDirectoryPath, String.valueOf(savedName)));
if (VERBOSE)
Util.verbose("Reading saved index file " + indexLocation);
this.indexStates.put(indexLocation, SAVED_STATE);
}
}
} else {
writeJavaLikeNamesFile();
this.javaLikeNamesChanged = false;
deleteIndexFiles();
}
readIndexMap();
return this.indexStates;
}
private IPath getParticipantsContainer(IndexLocation indexLocation) {
if (this.participantsContainers == null) {
readParticipantsIndexNamesFile();
}
return (IPath)this.participantsContainers.get(indexLocation);
}
private IPath getJavaPluginWorkingLocation() {
if (this.javaPluginLocation != null) return this.javaPluginLocation;
IPath stateLocation = JavaCore.getPlugin().getStateLocation();
return this.javaPluginLocation = stateLocation;
}
private File getSavedIndexesDirectory() {
return new File(getJavaPluginWorkingLocation().toOSString());
}
private boolean hasJavaLikeNamesChanged() {
char[][] currentNames = Util.getJavaLikeExtensions();
int current = currentNames.length;
char[][] prevNames = readJavaLikeNamesFile();
if (prevNames == null) {
if (VERBOSE && current != 1)
Util.verbose("No Java like names found and there is atleast one non-default javaLikeName", System.err);
return (current != 1);
}
int prev = prevNames.length;
if (current != prev) {
if (VERBOSE)
Util.verbose("Java like names have changed", System.err);
return true;
}
if (current > 1) {
System.arraycopy(currentNames, 0, currentNames = new char[current][], 0, current);
Util.sort(currentNames);
}
for (int i = 0; i < current; i++) {
if (!CharOperation.equals(currentNames[i],prevNames[i])) {
if (VERBOSE)
Util.verbose("Java like names have changed", System.err);
return true;
}
}
return false;
}
public void indexDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexLocation) {
try {
searchDocument.setIndex(index);
searchParticipant.indexDocument(searchDocument, indexLocation);
} finally {
searchDocument.setIndex(null);
}
}
public void indexResolvedDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexLocation) {
searchParticipant.resolveDocument(searchDocument);
ReadWriteMonitor monitor = index.monitor;
if (monitor == null)
return;
try {
monitor.enterWrite();
searchDocument.setIndex(index);
searchParticipant.indexResolvedDocument(searchDocument, indexLocation);
} finally {
searchDocument.setIndex(null);
monitor.exitWrite();
}
}
public void indexAll(IProject project) {
if (JavaCore.getPlugin() == null) return;
try {
disable();
try {
JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
JavaProject javaProject = (JavaProject) model.getJavaProject(project);
IClasspathEntry[] entries = javaProject.getResolvedClasspath();
for (int i = 0; i < entries.length; i++) {
IClasspathEntry entry= entries[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
indexLibrary(entry.getPath(), project, ((ClasspathEntry)entry).getLibraryIndexLocation());
}
} catch(JavaModelException e){
}
IndexRequest request = new IndexAllProject(project, this);
if (!isJobWaiting(request))
request(request);
} finally {
enable();
}
}
public void indexLibrary(IPath path, IProject requestingProject, URL indexURL) {
this.indexLibrary(path, requestingProject, indexURL, false);
}
private IndexRequest getRequest(Object target, IPath jPath, IndexLocation indexFile, IndexManager manager, boolean updateIndex) {
return isJrt(((File) target).getName()) ? new AddJrtToIndex(jPath, indexFile, this, updateIndex) :
new AddJarFileToIndex(jPath, indexFile, this, updateIndex);
}
private boolean isJrt(String fileName) {
return fileName != null && fileName.endsWith(JRTUtil.JRT_FS_JAR);
}
public void indexLibrary(IPath path, IProject requestingProject, URL indexURL, final boolean updateIndex) {
IndexLocation indexFile = null;
boolean forceIndexUpdate = false;
if(indexURL != null) {
if(IS_MANAGING_PRODUCT_INDEXES_PROPERTY) {
indexFile = computeIndexLocation(path, indexURL);
if(!updateIndex && !indexFile.exists()) {
forceIndexUpdate = true;
}
else {
forceIndexUpdate = updateIndex;
}
}
else {
indexFile = IndexLocation.createIndexLocation(indexURL);
}
}
if (JavaCore.getPlugin() == null) return;
IndexRequest request = null;
Object target = JavaModel.getTarget(path, true);
if (target instanceof IFile) {
request = isJrt(((IFile) target).getFullPath().toOSString()) ?
new AddJrtToIndex((IFile) target, indexFile, this, forceIndexUpdate) :
new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate);
} else if (target instanceof File) {
request = getRequest(target, path, indexFile, this, forceIndexUpdate);
} else if (target instanceof IContainer) {
request = new IndexBinaryFolder((IContainer) target, this);
} else {
return;
}
if (!isJobWaiting(request))
request(request);
}
synchronized boolean addIndex(IPath containerPath, IndexLocation indexFile) {
getIndexStates().put(indexFile, REUSE_STATE);
this.indexLocations.put(containerPath, indexFile);
Index index = getIndex(containerPath, indexFile, true, false);
if (index == null) {
indexFile.close();
this.indexLocations.put(containerPath, null);
return false;
}
writeIndexMapFile();
return true;
}
public void indexSourceFolder(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
IProject project = javaProject.getProject();
if (this.jobEnd > this.jobStart) {
IndexRequest request = new IndexAllProject(project, this);
if (isJobWaiting(request)) return;
}
request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this));
}
public synchronized void jobWasCancelled(IPath containerPath) {
IndexLocation indexLocation = computeIndexLocation(containerPath);
Index index = getIndex(indexLocation);
if (index != null) {
index.monitor = null;
this.indexes.removeKey(indexLocation);
}
updateIndexState(indexLocation, UNKNOWN_STATE);
}
@Override
protected synchronized void moveToNextJob() {
this.needToSave = true;
super.moveToNextJob();
}
@Override
protected void notifyIdle(long idlingTime){
if (idlingTime > 1000 && this.needToSave) saveIndexes();
}
@Override
public String processName(){
return Messages.process_name;
}
private char[][] readJavaLikeNamesFile() {
try {
String pathName = getJavaPluginWorkingLocation().toOSString();
File javaLikeNamesFile = new File(pathName, "javaLikeNames.txt");
if (!javaLikeNamesFile.exists())
return null;
char[] javaLikeNames = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(javaLikeNamesFile, null);
if (javaLikeNames.length > 0) {
char[][] names = CharOperation.splitOn('\n', javaLikeNames);
return names;
}
} catch (IOException ignored) {
if (VERBOSE)
Util.verbose("Failed to read javaLikeNames file");
}
return null;
}
private void rebuildIndex(IndexLocation indexLocation, IPath containerPath) {
rebuildIndex(indexLocation, containerPath, false);
}
private void rebuildIndex(IndexLocation indexLocation, IPath containerPath, final boolean updateIndex) {
Object target = JavaModel.getTarget(containerPath, true);
if (target == null) return;
if (VERBOSE)
Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath);
updateIndexState(indexLocation, REBUILDING_STATE);
IndexRequest request = null;
if (target instanceof IProject) {
IProject p = (IProject) target;
if (JavaProject.hasJavaNature(p))
request = new IndexAllProject(p, this);
} else if (target instanceof IFolder) {
request = new IndexBinaryFolder((IFolder) target, this);
} else if (target instanceof IFile) {
request = isJrt(((IFile) target).getFullPath().toOSString()) ?
new AddJrtToIndex((IFile) target, null, this, updateIndex) :
new AddJarFileToIndex((IFile) target, null, this, updateIndex);
} else if (target instanceof File) {
request = getRequest(target, containerPath, null, this, updateIndex);
}
if (request != null)
request(request);
}
public synchronized Index recreateIndex(IPath containerPath) {
String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
try {
IndexLocation indexLocation = computeIndexLocation(containerPath);
Index index = getIndex(indexLocation);
ReadWriteMonitor monitor = index == null ? null : index.monitor;
if (VERBOSE)
Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPathString);
index = new Index(indexLocation, containerPathString, false );
this.indexes.put(indexLocation, index);
index.monitor = monitor;
return index;
} catch (IOException e) {
if (VERBOSE) {
Util.verbose("-> failed to recreate index for path: "+containerPathString);
e.printStackTrace();
}
return null;
}
}
public void remove(String containerRelativePath, IPath indexedContainer){
request(new RemoveFromIndex(containerRelativePath, indexedContainer, this));
}
public synchronized void removeIndex(IPath containerPath) {
if (VERBOSE || DEBUG)
Util.verbose("removing index " + containerPath);
IndexLocation indexLocation = computeIndexLocation(containerPath);
Index index = getIndex(indexLocation);
File indexFile = null;
if (index != null) {
index.monitor = null;
indexFile = index.getIndexFile();
}
if (indexFile == null)
indexFile = indexLocation.getIndexFile();
if (this.indexStates.get(indexLocation) == REUSE_STATE) {
indexLocation.close();
this.indexLocations.put(containerPath, null);
} else if (indexFile != null && indexFile.exists()) {
if (DEBUG)
Util.verbose("removing index file " + indexFile);
indexFile.delete();
}
this.indexes.removeKey(indexLocation);
if (IS_MANAGING_PRODUCT_INDEXES_PROPERTY) {
this.indexLocations.removeKey(containerPath);
}
updateIndexState(indexLocation, null);
}
public synchronized void removeIndexPath(IPath path) {
if (VERBOSE || DEBUG)
Util.verbose("removing index path " + path);
Object[] keyTable = this.indexes.keyTable;
Object[] valueTable = this.indexes.valueTable;
IndexLocation[] locations = null;
int max = this.indexes.elementSize;
int count = 0;
for (int i = 0, l = keyTable.length; i < l; i++) {
IndexLocation indexLocation = (IndexLocation) keyTable[i];
if (indexLocation == null)
continue;
if (indexLocation.startsWith(path)) {
Index index = (Index) valueTable[i];
index.monitor = null;
if (locations == null)
locations = new IndexLocation[max];
locations[count++] = indexLocation;
if (this.indexStates.get(indexLocation) == REUSE_STATE) {
indexLocation.close();
} else {
if (DEBUG)
Util.verbose("removing index file " + indexLocation);
indexLocation.delete();
}
} else {
max--;
}
}
if (locations != null) {
for (int i = 0; i < count; i++)
this.indexes.removeKey(locations[i]);
removeIndexesState(locations);
if (this.participantsContainers != null) {
boolean update = false;
for (int i = 0; i < count; i++) {
if (this.participantsContainers.get(locations[i]) != null) {
update = true;
this.participantsContainers.removeKey(locations[i]);
}
}
if (update) writeParticipantsIndexNamesFile();
}
}
}
public synchronized void removeIndexFamily(IPath path) {
ArrayList toRemove = null;
Object[] containerPaths = this.indexLocations.keyTable;
for (int i = 0, length = containerPaths.length; i < length; i++) {
IPath containerPath = (IPath) containerPaths[i];
if (containerPath == null) continue;
if (path.isPrefixOf(containerPath)) {
if (toRemove == null)
toRemove = new ArrayList();
toRemove.add(containerPath);
}
}
if (toRemove != null)
for (int i = 0, length = toRemove.size(); i < length; i++)
removeIndex((IPath) toRemove.get(i));
}
public void removeSourceFolderFromIndex(JavaProject javaProject, IPath sourceFolder, char[][] inclusionPatterns, char[][] exclusionPatterns) {
IProject project = javaProject.getProject();
if (this.jobEnd > this.jobStart) {
IndexRequest request = new IndexAllProject(project, this);
if (isJobWaiting(request)) return;
}
request(new RemoveFolderFromIndex(sourceFolder, inclusionPatterns, exclusionPatterns, project, this));
}
@Override
public void reset() {
super.reset();
synchronized (this) {
if (this.indexes != null) {
this.indexes = new SimpleLookupTable();
this.indexStates = null;
}
this.indexLocations = new SimpleLookupTable();
this.javaPluginLocation = null;
}
}
public synchronized boolean resetIndex(IPath containerPath) {
String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString();
try {
IndexLocation indexLocation = computeIndexLocation(containerPath);
Index index = getIndex(indexLocation);
if (VERBOSE) {
Util.verbose("-> reseting index: "+indexLocation+" for path: "+containerPathString);
}
if (index == null) {
return recreateIndex(containerPath) != null;
}
index.reset();
return true;
} catch (IOException e) {
if (VERBOSE) {
Util.verbose("-> failed to reset index for path: "+containerPathString);
e.printStackTrace();
}
return false;
}
}
public void savePreBuiltIndex(Index index) throws IOException {
if (index.hasChanged()) {
if (VERBOSE)
Util.verbose("-> saving pre-build index " + index.getIndexLocation());
index.save();
}
synchronized (this) {
updateIndexState(index.getIndexLocation(), REUSE_STATE);
}
}
public void saveIndex(Index index) throws IOException {
if (index.hasChanged()) {
if (VERBOSE)
Util.verbose("-> saving index " + index.getIndexLocation());
index.save();
}
synchronized (this) {
IPath containerPath = new Path(index.containerPath);
if (this.jobEnd > this.jobStart) {
for (int i = this.jobEnd; i > this.jobStart; i--) {
IJob job = this.awaitingJobs[i];
if (job instanceof IndexRequest)
if (((IndexRequest) job).containerPath.equals(containerPath)) return;
}
}
IndexLocation indexLocation = computeIndexLocation(containerPath);
updateIndexState(indexLocation, SAVED_STATE);
}
}
public void saveIndexes() {
ArrayList toSave = new ArrayList();
synchronized(this) {
Object[] valueTable = this.indexes.valueTable;
for (int i = 0, l = valueTable.length; i < l; i++) {
Index index = (Index) valueTable[i];
if (index != null)
toSave.add(index);
}
}
boolean allSaved = true;
for (int i = 0, length = toSave.size(); i < length; i++) {
Index index = (Index) toSave.get(i);
ReadWriteMonitor monitor = index.monitor;
if (monitor == null) continue;
try {
monitor.enterRead();
if (index.hasChanged()) {
if (monitor.exitReadEnterWrite()) {
try {
saveIndex(index);
} catch(IOException e) {
if (VERBOSE) {
Util.verbose("-> got the following exception while saving:", System.err);
e.printStackTrace();
}
allSaved = false;
} finally {
monitor.exitWriteEnterRead();
}
} else {
allSaved = false;
}
}
} finally {
monitor.exitRead();
}
}
if (this.participantsContainers != null && this.participantUpdated) {
writeParticipantsIndexNamesFile();
this.participantUpdated = false;
}
this.needToSave = !allSaved;
}
public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath container, final IndexLocation indexLocation, final SearchParticipant searchParticipant) {
request(new IndexRequest(container, this) {
@Override
public boolean execute(IProgressMonitor progressMonitor) {
if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;
Index index = getIndex(this.containerPath, indexLocation, true, true );
if (index == null) return true;
ReadWriteMonitor monitor = index.monitor;
if (monitor == null) return true;
final Path indexPath = new Path(indexLocation.getCanonicalFilePath());
try {
monitor.enterWrite();
indexDocument(searchDocument, searchParticipant, index, indexPath);
} finally {
monitor.exitWrite();
}
if (searchDocument.shouldIndexResolvedDocument()) {
indexResolvedDocument(searchDocument, searchParticipant, index, indexPath);
}
return true;
}
@Override
public String toString() {
return "indexing " + searchDocument.getPath();
}
@Override
public boolean waitNeeded() {
return false;
}
});
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer(10);
buffer.append(super.toString());
buffer.append("In-memory indexes:\n");
int count = 0;
Object[] valueTable = this.indexes.valueTable;
for (int i = 0, l = valueTable.length; i < l; i++) {
Index index = (Index) valueTable[i];
if (index != null)
buffer.append(++count).append(" - ").append(index.toString()).append('\n');
}
return buffer.toString();
}
private void readIndexMap() {
try {
char[] indexMaps = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(this.indexNamesMapFile, null);
char[][] names = CharOperation.splitOn('\n', indexMaps);
if (names.length >= 3) {
String savedSignature = DiskIndex.SIGNATURE;
if (savedSignature.equals(new String(names[0]))) {
for (int i = 1, l = names.length-1 ; i < l ; i+=2) {
IndexLocation indexPath = IndexLocation.createIndexLocation(new URL(new String(names[i])));
if (indexPath == null) continue;
this.indexLocations.put(new Path(new String(names[i+1])), indexPath );
this.indexStates.put(indexPath, REUSE_STATE);
}
}
}
} catch (IOException ignored) {
if (VERBOSE)
Util.verbose("Failed to read saved index file names");
}
return;
}
private void readParticipantsIndexNamesFile() {
SimpleLookupTable containers = new SimpleLookupTable(3);
try {
char[] participantIndexNames = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(this.participantIndexNamesFile, null);
if (participantIndexNames.length > 0) {
char[][] names = CharOperation.splitOn('\n', participantIndexNames);
if (names.length >= 3) {
if (DiskIndex.SIGNATURE.equals(new String(names[0]))) {
for (int i = 1, l = names.length-1 ; i < l ; i+=2) {
IndexLocation indexLocation = new FileIndexLocation(new File(new String(names[i])), true);
containers.put(indexLocation, new Path(new String(names[i+1])));
}
}
}
}
} catch (IOException ignored) {
if (VERBOSE)
Util.verbose("Failed to read participant index file names");
}
this.participantsContainers = containers;
return;
}
private synchronized void removeIndexesState(IndexLocation[] locations) {
getIndexStates();
int length = locations.length;
boolean changed = false;
for (int i=0; i<length; i++) {
if (locations[i] == null) continue;
if ((this.indexStates.removeKey(locations[i]) != null)) {
changed = true;
if (VERBOSE) {
Util.verbose("-> index state updated to: ? for: "+locations[i]);
}
}
}
if (!changed) return;
writeSavedIndexNamesFile();
writeIndexMapFile();
}
private synchronized void updateIndexState(IndexLocation indexLocation, Integer indexState) {
if (indexLocation == null)
throw new IllegalArgumentException();
getIndexStates();
if (indexState != null) {
if (indexState.equals(this.indexStates.get(indexLocation))) return;
this.indexStates.put(indexLocation, indexState);
} else {
if (!this.indexStates.containsKey(indexLocation)) return;
this.indexStates.removeKey(indexLocation);
}
writeSavedIndexNamesFile();
if (VERBOSE) {
if (indexState == null) {
Util.verbose("-> index state removed for: "+indexLocation);
} else {
String state = "?";
if (indexState == SAVED_STATE) state = "SAVED";
else if (indexState == UPDATING_STATE) state = "UPDATING";
else if (indexState == UNKNOWN_STATE) state = "UNKNOWN";
else if (indexState == REBUILDING_STATE) state = "REBUILDING";
else if (indexState == REUSE_STATE) state = "REUSE";
Util.verbose("-> index state updated to: " + state + " for: "+indexLocation);
}
}
}
public void updateParticipant(IPath indexPath, IPath containerPath) {
if (this.participantsContainers == null) {
readParticipantsIndexNamesFile();
}
IndexLocation indexLocation = new FileIndexLocation(indexPath.toFile(), true);
if (this.participantsContainers.get(indexLocation) == null) {
this.participantsContainers.put(indexLocation, containerPath);
this.participantUpdated = true;
}
}
private void writeJavaLikeNamesFile() {
BufferedWriter writer = null;
String pathName = getJavaPluginWorkingLocation().toOSString();
try {
char[][] currentNames = Util.getJavaLikeExtensions();
int length = currentNames.length;
if (length > 1) {
System.arraycopy(currentNames, 0, currentNames=new char[length][], 0, length);
Util.sort(currentNames);
}
File javaLikeNamesFile = new File(pathName, "javaLikeNames.txt");
writer = new BufferedWriter(new FileWriter(javaLikeNamesFile));
for (int i = 0; i < length-1; i++) {
writer.write(currentNames[i]);
writer.write('\n');
}
if (length > 0)
writer.write(currentNames[length-1]);
} catch (IOException ignored) {
if (VERBOSE)
Util.verbose("Failed to write javaLikeNames file", System.err);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
}
}
}
}
private void writeIndexMapFile() {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(this.indexNamesMapFile));
writer.write(DiskIndex.SIGNATURE);
writer.write('\n');
Object[] keys = this.indexStates.keyTable;
Object[] states = this.indexStates.valueTable;
for (int i = 0, l = states.length; i < l; i++) {
IndexLocation location = (IndexLocation)keys[i];
if (location != null && states[i] == REUSE_STATE) {
IPath container = (IPath)this.indexLocations.keyForValue(location);
if (container != null) {
writer.write(location.toString());
writer.write('\n');
writer.write(container.toOSString());
writer.write('\n');
}
}
}
} catch (IOException ignored) {
if (VERBOSE)
Util.verbose("Failed to write saved index file names", System.err);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
}
}
}
}
private void writeParticipantsIndexNamesFile() {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(this.participantIndexNamesFile));
writer.write(DiskIndex.SIGNATURE);
writer.write('\n');
Object[] indexFiles = this.participantsContainers.keyTable;
Object[] containers = this.participantsContainers.valueTable;
for (int i = 0, l = indexFiles.length; i < l; i++) {
IndexLocation indexFile = (IndexLocation)indexFiles[i];
if (indexFile != null) {
writer.write(indexFile.getIndexFile().getPath());
writer.write('\n');
writer.write(((IPath)containers[i]).toOSString());
writer.write('\n');
}
}
} catch (IOException ignored) {
if (VERBOSE)
Util.verbose("Failed to write participant index file names", System.err);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
}
}
}
}
private void writeSavedIndexNamesFile() {
Object[] keys = this.indexStates.keyTable;
Object[] states = this.indexStates.valueTable;
int numToSave = 0;
for (int i = 0, l = states.length; i < l; i++) {
IndexLocation key = (IndexLocation) keys[i];
if (key != null && states[i] == SAVED_STATE) {
numToSave++;
}
}
char[][] arrays = new char[numToSave][];
int idx = 0;
for (int i = 0, l = states.length; i < l; i++) {
IndexLocation key = (IndexLocation) keys[i];
if (key != null && states[i] == SAVED_STATE) {
arrays[idx++] = key.fileName().toCharArray();
}
}
this.nameRegistry.write(arrays);
}
}