diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaIndexTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaIndexTests.java index 1893d3f..f8e8a9f 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaIndexTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaIndexTests.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2012 IBM Corporation and others. + * Copyright (c) 2012, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -864,3 +864,70 @@ } } + public void testManagingPreBuildIndexFile() throws CoreException, IOException { + + // locate the JDT core preference + String prefNodeName = "org.eclipse.jdt.core"; + IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(prefNodeName); + if(prefs == null) { + fail("The preferences for '" + prefNodeName + "' could not be located."); + } + // create the pre-built index + File indexFile = null; + String jarFilePath = getExternalResourcePath("Test.jar"); + File jarFile = new File(jarFilePath); + IJavaProject p = null; + try { + createJar(new String[] { + "pkg/Test.java", + "package pkg;\n" + + "public class Test {\n" + + " protected Test(int i) {}\n" + + " protected void helloWorld() {}\n" + + "}"}, jarFilePath); + indexFile = new File(getExternalResourcePath("Test.index")); + JavaIndexer.generateIndexForJar(jarFilePath, indexFile.getAbsolutePath()); + // create project P and add the Test.jar to the classpath (associate the index to it) + p = createJavaProject("P"); + Path libPath = new Path(jarFilePath); + IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, indexFile.toURI().toURL().toString()); + IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false); + this.setClasspath(p, new IClasspathEntry[] {entry}); + AbstractJavaModelTests.waitUntilIndexesReady(); + // verify the current index is correct + this.resultCollector = new JavaSearchResultCollector(); + this.search("helloWorld", METHOD, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p})); + this.assertSearchResults(getExternalPath() + "Test.jar void pkg.Test.helloWorld()"); + // restart the product so the index manager enables management of pre-build indexes + prefs.put(JavaCore.MANAGE_PREBUILT_INDEXES, JavaCore.ENABLED); + this.simulateExit(); + // update the class file (when the product is not running) by changing + // the method signature (simulate the contents of a JAR file changing) + createJar(new String[] { + "pkg/Test.java", + "package pkg;\n" + + "public class Test {\n" + + " protected Test(int i) {}\n" + + " protected void helloWorld(int i) {}\n" + + "}"}, jarFilePath); + this.simulateRestart(); + JavaCore.initializeAfterLoad(null); + AbstractJavaModelTests.waitUntilIndexesReady(); + // verify that the index is updated + this.resultCollector = new JavaSearchResultCollector(); + this.search("helloWorld", METHOD, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p})); + this.assertSearchResults(getExternalPath() + "Test.jar void pkg.Test.helloWorld(int)"); + } + finally { + // restart the product so the index manager disables management of pre-build indexes + prefs.put(JavaCore.MANAGE_PREBUILT_INDEXES, JavaCore.DISABLED); + // clean-up artifacts that were created + if(p != null) { + deleteProject("P"); + } + if (indexFile != null) { + indexFile.delete(); + } + jarFile.delete(); + } + } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index 1af5510..4ac884e 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -2172,4 +2172,16 @@ */ public static final String TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC = PLUGIN_ID + ".timeoutForParameterNameFromAttachedJavadoc"; //$NON-NLS-1$ + /** + * Core option ID: The indexer will manage (update or delete) pre-built indexes + *

When enabled, the indexer will manage any pre-built index files

+ *
+ *
Option id:
"org.eclipse.jdt.core.index.manageProductIndexes"
+ *
Possible values:
{ "enabled", "disabled" }
+ *
Default:
"disabled"
+ *
+ * @since 3.9 + * @category CoreOptionID + */ + public static final String MANAGE_PREBUILT_INDEXES = PLUGIN_ID + ".index.manageProductIndexes"; //$NON-NLS-1$ /** diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java index c36e288..8accbb6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -999,5 +999,5 @@ this.manager.indexManager.removeIndex(entryPath); // then index the jar - this.manager.indexManager.indexLibrary(entryPath, project.getProject(), ((ClasspathEntry)entries[j]).getLibraryIndexLocation()); + this.manager.indexManager.indexLibrary(entryPath, project.getProject(), ((ClasspathEntry)entries[j]).getLibraryIndexLocation(), true); } else { URL indexLocation = ((ClasspathEntry)entries[j]).getLibraryIndexLocation(); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java index 91c6dde..3756005 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -94,4 +94,6 @@ // Time out for parameter names defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$ + // update product index (default: disabled) + defaultOptionsMap.put(JavaCore.MANAGE_PREBUILT_INDEXES, JavaCore.DISABLED); // Store default values to default preferences diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java index cfa351a..a7e1319 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -2256,4 +2256,6 @@ // Time out for parameter names defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$ + // update product index (default: disabled) + defaultOptionsMap.put(JavaCore.MANAGE_PREBUILT_INDEXES, JavaCore.DISABLED); return new Hashtable(defaultOptionsMap); diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java index 46dfe21..c88ed49 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -45,14 +45,23 @@ Scanner scanner; 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) { // external JAR scenario - no resource super(jarPath, manager); this.indexFileURL = indexFile; + this.forceIndexUpdate = updateIndex; } public boolean equals(Object o) { @@ -76,5 +85,5 @@ if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true; - if (this.indexFileURL != null) { + if (this.hasPreBuiltIndex()) { boolean added = this.manager.addIndex(this.containerPath, this.indexFileURL); if (added) return true; @@ -292,8 +301,20 @@ } protected Integer updatedIndexState() { - return IndexManager.REBUILDING_STATE; + + Integer updateState = null; + if(this.hasPreBuiltIndex()) { + updateState = IndexManager.REUSE_STATE; + } + else { + updateState = IndexManager.REBUILDING_STATE; + } + return updateState; } public String toString() { return "indexing " + this.containerPath.toString(); //$NON-NLS-1$ } -} + + protected boolean hasPreBuiltIndex() { + return !this.forceIndexUpdate && ((this.indexFileURL != null) && this.indexFileURL.exists()); + } +} \ No newline at end of file diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java index d130e0f..8c4e265 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java @@ -1,4 +1,4 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -68,8 +68,23 @@ private boolean participantUpdated = false; + // should JDT manage (update, delete as needed) pre-built indexes? + private Boolean manageUserIndexes = null; + // Debug public static boolean DEBUG = false; - public synchronized void aboutToUpdateIndex(IPath containerPath, Integer newIndexState) { +private boolean isManagingPreBuiltIndexes() { + if (this.manageUserIndexes == null) { + String manageIndexPropertyValue = JavaCore.getOption(JavaCore.MANAGE_PREBUILT_INDEXES); + if (manageIndexPropertyValue != null) { + this.manageUserIndexes = Boolean.valueOf(JavaCore.ENABLED.equals(manageIndexPropertyValue)); + } else { + this.manageUserIndexes = Boolean.FALSE; + } + } + return this.manageUserIndexes.booleanValue(); + } + +public synchronized void aboutToUpdateIndex(IPath containerPath, Integer newIndexState) { // newIndexState is either UPDATING_STATE or REBUILDING_STATE // must tag the index as inconsistent, in case we exit before the update job is started @@ -137,4 +152,35 @@ } deleteIndexFiles(knownPaths); +} +/** + * Compute the pre-built index location for a specified URL + */ +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); + // update caches + indexLocation = (IndexLocation) getIndexStates().getKey(indexLocation); + this.indexLocations.put(containerPath, indexLocation); + } + } + else { + // an existing index location exists - make sure it has not changed (i.e. the URL has not changed) + URL existingURL = indexLocation.getUrl(); + if (newIndexURL != null) { + // if either URL is different then the index location has been updated so rebuild. + if(!newIndexURL.equals(existingURL)) { + // URL has changed so remove the old index and create a new one + this.removeIndex(containerPath); + // create a new one + indexLocation = IndexLocation.createIndexLocation(newIndexURL); + // update caches + indexLocation = (IndexLocation) getIndexStates().getKey(indexLocation); + this.indexLocations.put(containerPath, indexLocation); + } + } + } + return indexLocation; } public synchronized IndexLocation computeIndexLocation(IPath containerPath) { @@ -494,18 +540,26 @@ request(request); } +public void indexLibrary(IPath path, IProject requestingProject, URL indexURL) { + this.indexLibrary(path, requestingProject, indexURL, false); +} + /** * Trigger addition of a library to an index * Note: the actual operation is performed in background */ -public void indexLibrary(IPath path, IProject requestingProject, URL indexURL) { +public void indexLibrary(IPath path, IProject requestingProject, URL indexURL, final boolean updateIndex) { // requestingProject is no longer used to cancel jobs but leave it here just in case - IndexLocation indexFile = indexURL != null ? IndexLocation.createIndexLocation(indexURL): null; + IndexLocation indexFile = null; + if (indexURL != null) { + indexFile = computeIndexLocation(path, indexURL); + } if (JavaCore.getPlugin() == null) return; IndexRequest request = null; + boolean forceIndexUpdate = this.isManagingPreBuiltIndexes() && updateIndex; Object target = JavaModel.getTarget(path, true); if (target instanceof IFile) { - request = new AddJarFileToIndex((IFile) target, indexFile, this); + request = new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate); } else if (target instanceof File) { - request = new AddJarFileToIndex(path, indexFile, this); + request = new AddJarFileToIndex(path, indexFile, this, forceIndexUpdate); } else if (target instanceof IContainer) { request = new IndexBinaryFolder((IContainer) target, this); @@ -676,4 +730,7 @@ } this.indexes.removeKey(indexLocation); + if (isManagingPreBuiltIndexes()) { + this.indexLocations.removeKey(containerPath); + } updateIndexState(indexLocation, null); } @@ -770,4 +827,5 @@ this.indexLocations = new SimpleLookupTable(); this.javaPluginLocation = null; + this.manageUserIndexes = null; } /** @@ -1014,4 +1072,5 @@ else if (indexState == UNKNOWN_STATE) state = "UNKNOWN"; //$NON-NLS-1$ else if (indexState == REBUILDING_STATE) state = "REBUILDING"; //$NON-NLS-1$ + else if (indexState == REUSE_STATE) state = "REUSE"; //$NON-NLS-1$ Util.verbose("-> index state updated to: " + state + " for: "+indexLocation); //$NON-NLS-1$ //$NON-NLS-2$ }