Skip to main content
summaryrefslogtreecommitdiffstats
blob: c56c43195aa093e8e3d8eaa5bdd5d7150d179236 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
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));
	}
}
}

Back to the top