blob: c56c43195aa093e8e3d8eaa5bdd5d7150d179236 [file] [log] [blame]
package org.eclipse.jdt.internal.core.search.indexing;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.internal.core.index.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.internal.core.search.indexing.*;
import org.eclipse.jdt.internal.core.search.Util;
import org.eclipse.jdt.internal.core.search.processing.*;
import org.eclipse.jdt.internal.core.*;
import org.eclipse.jdt.internal.core.index.impl.*;
import org.eclipse.jdt.core.JavaCore;
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class IndexManager extends JobManager implements IIndexConstants {
/* number of file contents in memory */
public static int MAX_FILES_IN_MEMORY = 0;
public IWorkspace workspace;
/* indexes */
Hashtable indexes = new Hashtable(5);
/* read write monitors */
private Hashtable monitors = new Hashtable(5);
/* need to save ? */
private boolean needToSave = false;
private static final CRC32 checksumCalculator = new CRC32();
private IPath javaPluginLocation = null;
/**
* Before processing all jobs, need to ensure that the indexes are up to date.
*/
public void activateProcessing() {
try {
Thread.currentThread().sleep(10000); // wait 10 seconds so as not to interfere with plugin startup
} catch (InterruptedException ie) {
}
checkIndexConsistency();
super.activateProcessing();
}
/**
* Trigger addition of a resource to an index
* Note: the actual operation is performed in background
*/
public void add(IFile resource){
if (JavaCore.getPlugin() == null || this.workspace == null) return;
String extension = resource.getFileExtension();
if ("java"/*nonNLS*/.equals(extension)){
AddCompilationUnitToIndex job = new AddCompilationUnitToIndex(resource, this);
if (this.awaitingJobsCount() < MAX_FILES_IN_MEMORY) {
job.initializeContents();
}
request(job);
} else if ("class"/*nonNLS*/.equals(extension)){
AddClassFileToIndex job = new AddClassFileToIndex(resource, this);
if (this.awaitingJobsCount() < MAX_FILES_IN_MEMORY) {
job.initializeContents();
}
request(job);
}
}
/**
* Ensures that indexes are up to date with workbench content. Typically
* it is invoked in background when activate the job processing.
*/
public void checkIndexConsistency() {
if (VERBOSE) System.out.println("STARTING - ensuring consistency"/*nonNLS*/);
boolean wasEnabled = isEnabled();
try {
disable();
if (this.workspace == null) return;
IProject[] projects = this.workspace.getRoot().getProjects();
for (int i = 0, max = projects.length; i < max; i++){
IProject project = projects[i];
// not only java project, given at startup nature may not have been set yet
if (project.isOpen()) {
indexAll(project);
}
}
} finally {
if (wasEnabled) enable();
if (VERBOSE) System.out.println("DONE - ensuring consistency"/*nonNLS*/);
}
}
private String computeIndexName(String pathString) {
byte[] pathBytes = pathString.getBytes();
checksumCalculator.reset();
checksumCalculator.update(pathBytes);
String fileName = Long.toString(checksumCalculator.getValue()) + ".index"/*nonNLS*/;
if (VERBOSE) System.out.println(" index name: "/*nonNLS*/ + pathString + " <----> "/*nonNLS*/ + fileName);
IPath indexPath = getJavaPluginWorkingLocation();
String indexDirectory = indexPath.toOSString();
if (indexDirectory.endsWith(File.separator)) {
return indexDirectory + fileName;
} else {
return indexDirectory + File.separator + fileName;
}
}
/**
* About to delete a project.
*/
public void deleting(IProject project) {
discardJobsUntilNextProjectAddition(project.getName());
IPath path = project.getFullPath();
IIndex index = (IIndex) indexes.get(path);
if (index != null){
indexes.remove(path);
monitors.remove(index);
}
}
/**
* Remove the index from cache for a given project.
* Passing null as a job family discards them all.
*/
public void discardJobsUntilNextProjectAddition(String jobFamily) {
boolean wasEnabled = isEnabled();
try {
disable();
// wait until current job has completed
while (thread != null && executing){
try {
Thread.currentThread().sleep(50);
} catch(InterruptedException e){
}
}
// flush and compact awaiting jobs
int loc = -1;
boolean foundProjectAddition = false;
for (int i = jobStart; i <= jobEnd; i++){
IJob currentJob = awaitingJobs[i];
awaitingJobs[i] = null;
if (jobFamily == null) continue; // discard
if (currentJob.belongsTo(jobFamily)){ // might discard
if (!(foundProjectAddition || (foundProjectAddition = currentJob instanceof IndexAllProject))) continue; // discard
}
awaitingJobs[++loc] = currentJob;
}
jobStart = 0;
jobEnd = loc;
} finally {
if (wasEnabled) enable();
}
}
/**
* Returns the index for a given project, if none then create an empty one.
* Note: if there is an existing index file already, it will be reused.
* Warning: Does not check whether index is consistent (not being used)
*/
public IIndex getIndex(IPath path) {
return this.getIndex(path, true);
}
/**
* Returns the index for a given project, if none and asked for then create an empty one.
* Note: if there is an existing index file already, it will be reused.
* Warning: Does not check whether index is consistent (not being used)
*/
public synchronized IIndex getIndex(IPath path, boolean mustCreate) {
IIndex index = (IIndex) indexes.get(path);
if (index == null) {
try {
// Compute canonical path
IPath canonicalPath = JavaProject.canonicalizedPath(path);
index = (IIndex) indexes.get(canonicalPath);
if (!mustCreate) return index;
if (index == null) {
// New index: add same index for given path and canonical path
String indexPath = computeIndexName(canonicalPath.toOSString());
index = IndexFactory.newIndex(indexPath, "Index for "/*nonNLS*/ + canonicalPath.toOSString());
indexes.put(canonicalPath, index);
indexes.put(path, index);
monitors.put(index, new ReadWriteMonitor());
} else {
// Index existed for canonical path, add it for given path
indexes.put(path, index);
}
} catch (IOException e) {
// The file could not be created. Possible reason: the project has been deleted.
return null;
}
}
//System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName());
return index;
}
private IPath getJavaPluginWorkingLocation() {
if (javaPluginLocation == null) {
javaPluginLocation = JavaCore.getPlugin().getStateLocation();
}
return javaPluginLocation;
}
/**
* Index access is controlled through a read-write monitor so as
* to ensure there is no concurrent read and write operations
* (only concurrent reading is allowed).
*/
public ReadWriteMonitor getMonitorFor(IIndex index){
return (ReadWriteMonitor)monitors.get(index);
}
/**
* Trigger addition of the entire content of a project
* Note: the actual operation is performed in background
*/
public void indexAll(IProject project){
if (JavaCore.getPlugin() == null || this.workspace == null) return;
// Also request indexing of binaries on the classpath
// determine the new children
try {
IJavaModel model = JavaModelManager.getJavaModel(this.workspace);
IJavaProject javaProject = ((JavaModel) model).getJavaProject(project);
IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
for (int i = 0; i < entries.length; i++) {
IClasspathEntry entry= entries[i];
if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY){
indexJarFile(entry.getPath(), project.getName());
}
}
} catch(JavaModelException e){ // cannot retrieve classpath info
}
request(new IndexAllProject(project, this));
}
/**
* Advance to the next available job, once the current one has been completed.
* Note: clients awaiting until the job count is zero are still waiting at this point.
*/
protected synchronized void moveToNextJob() {
// remember that one job was executed, and we will need to save indexes at some point
needToSave = true;
super.moveToNextJob();
}
/**
* No more job awaiting.
*/
protected void notifyIdle(long idlingTime){
if (idlingTime > 1000 && needToSave) saveIndexes();
}
/**
* Name of the background process
*/
public String processName(){
return Util.bind("process.name"/*nonNLS*/, IndexManager.class.getName());
}
/**
* Recreates the index for a given path, keeping the same read-write monitor.
* Returns the new empty index or null if it didn't exist before.
* Warning: Does not check whether index is consistent (not being used)
*/
public synchronized IIndex recreateIndex(IPath path) {
IIndex index = (IIndex) indexes.get(path);
if (index != null) {
try {
// Compute canonical path
IPath canonicalPath = JavaProject.canonicalizedPath(path);
// Add same index for given path and canonical path
String indexPath = computeIndexName(canonicalPath.toOSString());
ReadWriteMonitor monitor = (ReadWriteMonitor)monitors.remove(index);
index = IndexFactory.newIndex(indexPath, "Index for "/*nonNLS*/ + canonicalPath.toOSString());
index.empty();
indexes.put(canonicalPath, index);
indexes.put(path, index);
monitors.put(index, monitor);
} catch (IOException e) {
// The file could not be created. Possible reason: the project has been deleted.
return null;
}
}
//System.out.println(" index name: " + path.toOSString() + " <----> " + index.getIndexFile().getName());
return index;
}
/**
* Trigger removal of a resource to an index
* Note: the actual operation is performed in background
*/
public void remove(String resourceName, IProject project){
request(new RemoveFromIndex(resourceName, project, this));
}
/**
* Flush current state
*/
public void reset(){
super.reset();
if (indexes != null){
indexes = new Hashtable(5);
monitors = new Hashtable(5);
}
javaPluginLocation = null;
}
/**
* Commit all index memory changes to disk
*/
public void saveIndexes(){
Enumeration indexList = indexes.elements();
while (indexList.hasMoreElements()){
try {
IIndex index = (IIndex)indexList.nextElement();
if (index == null) continue; // index got deleted since acquired
ReadWriteMonitor monitor = getMonitorFor(index);
if (monitor == null) continue; // index got deleted since acquired
try {
monitor.enterWrite();
if (IndexManager.VERBOSE) System.out.println("-> merging index : "/*nonNLS*/+index.getIndexFile());
index.save();
} finally {
monitor.exitWrite();
}
} catch(IOException e){
// Index file has been deleted
}
}
needToSave = false;
}
/**
* Trigger addition of a resource to an index
* Note: the actual operation is performed in background
*/
public void indexJarFile(IPath path, String projectName) {
if (JavaCore.getPlugin() == null || this.workspace == null) return;
Object target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), path, true);
if (target instanceof IFile) {
request(new AddJarFileToIndex((IFile)target, this, projectName));
} else if (target instanceof java.io.File){
request(new AddJarFileToIndex(path, this, projectName));
}
}
}