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
new file mode 100644
index 0000000..c15475f
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaIndexTests.java
@@ -0,0 +1,765 @@
+/*******************************************************************************
+ * Copyright (c) 2011 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
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.model;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.Test;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jdt.core.ClasspathContainerInitializer;
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.index.*;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.UserLibraryClasspathContainer;
+import org.osgi.service.prefs.BackingStoreException;
+
+public class JavaIndexTests extends AbstractJavaSearchTests {
+
+ static {
+ // TESTS_NAMES = new String[] {"testPlatformIndexFile"};
+ }
+ public JavaIndexTests(String name) {
+ super(name);
+ }
+
+ public static Test suite() {
+ return buildModelTestSuite(JavaIndexTests.class);
+ }
+ // Test that the index file is really generated.
+ public void testGenerateIndex() throws IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ assertTrue(new File(indexFilePath).exists());
+ } finally {
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // Test that the index file and the jar can be deleted after the indexing is done
+ // This is to ensure that the files are closed
+ public void testDeleteIndexedFile() {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ assertTrue("Could not delete the index file", new File(indexFilePath).delete());
+ assertTrue("Could not delete the jar file", new File(jarFilePath).delete());
+ } catch (IOException e) {
+ assertFalse("Test failed", true);
+ }
+ }
+
+ // Test that search works fine with the index file
+ public void testUseIndex() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ long modified = new File(indexFilePath).lastModified();
+
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+
+ waitUntilIndexesReady();
+
+ // Test that specified index file is really used
+ java.io.File indexFile = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile();
+ assertEquals("Specified index file is not being used", indexFilePath,indexFile.toString());
+
+ // Test that search works properly
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ // Ensure that the index file is not modified
+ assertEquals(modified, new File(indexFilePath).lastModified());
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // Test that the same index file is used even after restarting
+ public void testUseIndexAfterRestart() throws IOException, CoreException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ long modified = new File(indexFilePath).lastModified();
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ simulateExitRestart();
+ getJavaModel().refreshExternalArchives(null, null);
+ waitUntilIndexesReady();
+
+ this.resultCollector = new JavaSearchResultCollector();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ java.io.File indexFile = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile();
+ assertEquals(indexFilePath,indexFile.toString());
+ // Ensure that the file is not modified
+ assertEquals(modified, new File(indexFilePath).lastModified());
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // Test that the same index file is used even after restarting
+ public void testUseIndexInternalJarAfterRestart() throws IOException, CoreException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = "/P/Test.jar";
+ try {
+ IJavaProject p = createJavaProject("P");
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ long modified = new File(indexFilePath).lastModified();
+ IPath libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults("\\P\\Test.jar pkg.Test");
+
+ simulateExitRestart();
+ getJavaModel().refreshExternalArchives(null, null);
+ waitUntilIndexesReady();
+
+ this.resultCollector = new JavaSearchResultCollector();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults("\\P\\Test.jar pkg.Test");
+
+ java.io.File indexFile = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile();
+ assertEquals(indexFilePath,indexFile.toString());
+ // Ensure that the file is not modified
+ assertEquals(modified, new File(indexFilePath).lastModified());
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ }
+ }
+
+ // Test that a jar file that gets modified after the index is created doesn't return new changes.
+ // This behavior might have to be modified but..
+ public void testModifyJarAfterIndex() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}",
+ "pkg/NewTest.java",
+ "package pkg;\n" +
+ "public class NewTest {\n" +
+ " protected NewTest(int i) {}\n" +
+ "}"}, jarFilePath);
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+ search("NewTest", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults("");
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // test a non-existent index
+ public void testNonExistentIndex() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ new File(indexFilePath).delete();
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // test a non-existent index
+ public void testNonExistentIndexRestart() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+
+ new File(indexFilePath).delete();
+
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ java.io.File indexFile = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile();
+ long modified = indexFile.lastModified();
+ assertEquals(modified, indexFile.lastModified());
+
+ simulateExitRestart();
+ getJavaModel().refreshExternalArchives(null,null);
+ waitUntilIndexesReady();
+
+ this.resultCollector = new JavaSearchResultCollector();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ indexFile = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile();
+ assertEquals("Index File should not have got modified",modified, indexFile.lastModified());
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // test that if the index is not existent after restart, it should build up a new index
+ public void testNonExistentIndexAfterRestart() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ "protected Test(int i) {}\n" + "}"
+ },jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ simulateExitRestart();
+ File indexFile = new File(indexFilePath);
+ indexFile.delete();
+ assertTrue(!indexFile.exists());
+ getJavaModel().refreshExternalArchives(null,null);
+ waitUntilIndexesReady();
+
+ this.resultCollector = new JavaSearchResultCollector();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // test a non-existent index which becomes existent after restart
+ public void testExistentIndexAfterRestart() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+
+ File indexFile = new File(indexFilePath);
+ indexFile.delete();
+ assertTrue(!indexFile.exists());
+
+ IJavaProject p = createJavaProject("P");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ simulateExitRestart();
+ getJavaModel().refreshExternalArchives(null,null);
+ waitUntilIndexesReady();
+
+ this.resultCollector = new JavaSearchResultCollector();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ indexFile = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile();
+ assertEquals(indexFilePath,indexFile.toString());
+ } finally {
+ deleteProject("P");
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+ // Test that the index file is not deleted when the project is deleted
+ public void testDeleteProject() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ IJavaProject p = createJavaProject("P");
+ createExternalFolder("externalLib");
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, "file:///"+indexFilePath);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+ deleteProject("P");
+ File f = new File(indexFilePath);
+ assertTrue(f.exists());
+ } finally {
+ new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+
+
+ // Test index file in platform
+ public void testPlatformIndexFile() throws CoreException, IOException {
+ String indexFilePath = null;
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ String indexUrl = "platform:/resource/P/Test.index";
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+
+ IJavaProject p = createJavaProject("P");
+ indexFilePath = p.getProject().getLocation().append("Test.index").toFile().getAbsolutePath();
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ long modified = new File(indexFilePath).lastModified();
+
+ Path libPath = new Path(jarFilePath);
+ IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, indexUrl);
+ IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false);
+ setClasspath(p, new IClasspathEntry[] {entry});
+ waitUntilIndexesReady();
+
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ String indexFileName = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile().getName();
+ assertEquals(indexFileName, "Test.index");
+
+ simulateExitRestart();
+ getJavaModel().refreshExternalArchives(null,null);
+ waitUntilIndexesReady();
+
+ this.resultCollector = new JavaSearchResultCollector();
+ search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p}));
+ assertSearchResults(getExternalPath() + "Test.jar pkg.Test");
+
+ indexFileName = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexFile().getName();
+ assertEquals(indexFileName, "Test.index");
+
+ assertEquals(modified, new File(indexFilePath).lastModified());
+ } finally {
+ deleteProject("P");
+ if (indexFilePath != null) new File(indexFilePath).delete();
+ new File(jarFilePath).delete();
+ }
+ }
+
+
+ public void testEditClasspath() throws CoreException, IOException {
+ String indexFilePath = getExternalResourcePath("Test.index");
+ String jarFilePath = getExternalResourcePath("Test.jar");
+ try {
+ createJar(new String[] {
+ "pkg/Test.java",
+ "package pkg;\n" +
+ "public class Test {\n" +
+ " protected Test(int i) {}\n" +
+ "}"}, jarFilePath);
+ JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath);
+ File f = new File(indexFilePath);
+ long modified = f.lastModified();
+ IJavaProject p = this.createJavaProject("P", new String[] {}, "bin");
+
+ String content = new String(
+ "\n"
+ + "
+ * An Ant task to generate the index file for the given jar path. + *
+ *
+ * <eclipse.buildJarIndex jarPath="Test.jar" indexPath="Test.index"/>
+ *
+ * For more information on Ant check out the website at http://jakarta.apache.org/ant/ . + *
+ *+ * This is not intended to be subclassed by users. + *
+ * @since 3.8 + */ +public class BuildJarIndex extends Task { + + private String jarPath; + private String indexPath; + + public void execute() throws BuildException { + if (this.jarPath == null) { + throw new BuildException(AntAdapterMessages.getString("buildJarIndex.jarFile.cannot.be.null")); //$NON-NLS-1$ + } + if (this.indexPath == null) { + throw new BuildException(AntAdapterMessages.getString("buildJarIndex.indexFile.cannot.be.null")); //$NON-NLS-1$ + } + + try { + JavaIndexer.generateIndexForJar(this.jarPath, this.indexPath); + } catch (IOException e) { + throw new BuildException(AntAdapterMessages.getString("buildJarIndex.ioexception.occured", e.getLocalizedMessage())); //$NON-NLS-1$ + } + } + + public void setJarPath(String path) { + this.jarPath = path; + } + + public void setIndexPath(String path) { + this.indexPath = path; + } +} diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/messages.properties b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/messages.properties index df61656..9cb9be2 100644 --- a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/messages.properties +++ b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/internal/antadapter/messages.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2006 IBM Corporation and others. +# Copyright (c) 2000, 2011 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 # which accompanies this distribution, and is available at @@ -19,3 +19,7 @@ checkDebugAttributes.property.argument.cannot.be.null=The property argument cannot be null checkDebugAttributes.ioexception.occured=IOException occurred while reading checkDebugAttributes.file.argument.must.be.a.classfile.or.a.jarfile=The file argument must be a .class or a .jar file + +buildJarIndex.jarFile.cannot.be.null=The jar file argument cannot be null +buildJarIndex.indexFile.cannot.be.null=The index file argument cannot be null +buildJarIndex.ioexception.occured=IOException - {0} diff --git a/org.eclipse.jdt.core/build.properties b/org.eclipse.jdt.core/build.properties index ff520f9..8e3f678 100644 --- a/org.eclipse.jdt.core/build.properties +++ b/org.eclipse.jdt.core/build.properties @@ -1,5 +1,5 @@ ############################################################################### -# Copyright (c) 2000, 2010 IBM Corporation and others. +# Copyright (c) 2000, 2011 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 # which accompanies this distribution, and is available at @@ -24,7 +24,8 @@ org.eclipse.jdt.core.jdom.*,\ org.eclipse.jdt.core.dom.*,\ org.eclipse.jdt.core.dom.rewrite.*,\ - org.eclipse.jdt.core.search.* + org.eclipse.jdt.core.search.*,\ + org.eclipse.jdt.core.index.* source.. = batch/,\ codeassist/,\ compiler/,\ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java index d90ab15..685c1a3 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2010 IBM Corporation and others. + * Copyright (c) 2005, 2011 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 * which accompanies this distribution, and is available at @@ -58,6 +58,16 @@ * @since 3.1 */ String JAVADOC_LOCATION_ATTRIBUTE_NAME = "javadoc_location"; //$NON-NLS-1$ + + /** + * Constant for the name of the index location attribute. + * + *The value for this attribute has to be the string representation of a URL. + * It should point to an existing index file in a folder or a jar. The URL can also be of platform protocol.
+ * + * @since 3.8 + */ + String INDEX_LOCATION_ATTRIBUTE_NAME = "index_location"; //$NON-NLS-1$ /** * Constant for the name of the optional attribute. The possible values diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java index b96cd44..b4da4b3 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathChange.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -335,7 +336,7 @@ boolean found = false; for (int j = 0; j < accumulatedRoots.size(); j++) { IPackageFragmentRoot root = (IPackageFragmentRoot) accumulatedRoots.elementAt(j); - if (!root.getPath().equals(oldRoot.getPath())) { + if (root.getPath().equals(oldRoot.getPath())) { found = true; break; } @@ -511,7 +512,7 @@ for (int i = 0; i < newLength; i++) { int index = classpathContains(this.oldResolvedClasspath, newResolvedClasspath[i]); - if (index == -1) { + if (index == -1 || newResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_LIBRARY) { // remote projects are not indexed in this project if (newResolvedClasspath[i].getEntryKind() == IClasspathEntry.CPE_PROJECT){ continue; @@ -519,19 +520,24 @@ // Request indexing int entryKind = newResolvedClasspath[i].getEntryKind(); + URL newurl = ((ClasspathEntry)newResolvedClasspath[i]).getLibraryIndexLocation(); switch (entryKind) { case IClasspathEntry.CPE_LIBRARY: boolean pathHasChanged = true; IPath newPath = newResolvedClasspath[i].getPath(); - for (int j = 0; j < oldLength; j++) { - IClasspathEntry oldEntry = this.oldResolvedClasspath[j]; - if (oldEntry.getPath().equals(newPath)) { + if (index != -1) { + IClasspathEntry oldEntry = this.oldResolvedClasspath[index]; + URL oldurl = ((ClasspathEntry)oldEntry).getLibraryIndexLocation(); + if (oldurl == null && newurl == null) { pathHasChanged = false; - break; + } else if (oldurl != null && newurl != null) { + pathHasChanged = !(newurl.equals(oldurl)); + } else if (oldurl != null) { + indexManager.removeIndex(newPath); } } if (pathHasChanged) { - indexManager.indexLibrary(newPath, this.project.getProject()); + indexManager.indexLibrary(newPath, this.project.getProject(), newurl); } break; case IClasspathEntry.CPE_SOURCE: diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java index 5656323..810a6b2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java @@ -17,6 +17,8 @@ import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -1524,6 +1526,33 @@ return JavaCore.getResolvedClasspathEntry(this); } + + /** + * This function computes the URL of the index location for this classpath entry. It returns null if the URL is + * invalid. + */ + public URL getLibraryIndexLocation() { + switch(getEntryKind()) { + case IClasspathEntry.CPE_LIBRARY : + case IClasspathEntry.CPE_VARIABLE : + break; + default : + return null; + } + if (this.extraAttributes == null) return null; + for (int i= 0; i < this.extraAttributes.length; i++) { + IClasspathAttribute attrib= this.extraAttributes[i]; + if (IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME.equals(attrib.getName())) { + String value = attrib.getValue(); + try { + return new URL(value); + } catch (MalformedURLException e) { + return null; + } + } + } + return null; + } /** * Validate a given classpath and output location for a project, using the following rules: 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 126fcc9..c36e288 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 @@ -13,6 +13,7 @@ package org.eclipse.jdt.internal.core; import java.io.File; +import java.net.URL; import java.util.*; import org.eclipse.core.resources.IContainer; @@ -997,8 +998,12 @@ // first remove the index so that it is forced to be re-indexed this.manager.indexManager.removeIndex(entryPath); // then index the jar - this.manager.indexManager.indexLibrary(entryPath, project.getProject()); + this.manager.indexManager.indexLibrary(entryPath, project.getProject(), ((ClasspathEntry)entries[j]).getLibraryIndexLocation()); } else { + URL indexLocation = ((ClasspathEntry)entries[j]).getLibraryIndexLocation(); + if (indexLocation != null) { // force reindexing, this could be faster rather than maintaining the list + this.manager.indexManager.indexLibrary(entryPath, project.getProject(), indexLocation); + } externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED); } } else { @@ -1009,7 +1014,7 @@ this.state.getExternalLibTimeStamps().put(entryPath, new Long(newTimeStamp)); // index the new jar this.manager.indexManager.removeIndex(entryPath); - this.manager.indexManager.indexLibrary(entryPath, project.getProject()); + this.manager.indexManager.indexLibrary(entryPath, project.getProject(), ((ClasspathEntry)entries[j]).getLibraryIndexLocation()); } } } else { // internal JAR @@ -2629,13 +2634,13 @@ switch (delta.getKind()) { case IResourceDelta.ADDED: // index the new jar - indexManager.indexLibrary(jarPath, root.getJavaProject().getProject()); + indexManager.indexLibrary(jarPath, root.getJavaProject().getProject(), root.getIndexPath()); break; case IResourceDelta.CHANGED: // first remove the index so that it is forced to be re-indexed indexManager.removeIndex(jarPath); // then index the jar - indexManager.indexLibrary(jarPath, root.getJavaProject().getProject()); + indexManager.indexLibrary(jarPath, root.getJavaProject().getProject(), root.getIndexPath()); break; case IResourceDelta.REMOVED: // the jar was physically removed: remove the index diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java index 5b18c19..3cd4d07 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core; +import java.net.URL; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipException; @@ -292,4 +293,15 @@ return; super.toStringAncestors(buffer); } + + public URL getIndexPath() { + try { + IClasspathEntry entry = ((JavaProject) getParent()).getClasspathEntryFor(getPath()); + if (entry != null) return ((ClasspathEntry)entry).getLibraryIndexLocation(); + } catch (JavaModelException e) { + // ignore exception + } + return null; + } + } diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml index 3784256..5d69788 100644 --- a/org.eclipse.jdt.core/plugin.xml +++ b/org.eclipse.jdt.core/plugin.xml @@ -1,7 +1,7 @@ @@ -196,6 +201,17 @@ + + +The search engine indexes all the elements referred in the classpath entries of the project into + * index files. These index files are used to search the elements faster. Indexing for bigger jars could + * take some time. To avoid this time, one can generate the index file and specify it when the jar is added + * to the classpath of the project.
+ * + * @since 3.8 + */ +public final class JavaIndexer { + + /** + * Generates the index file for the specified jar. + * @param pathToJar The full path to the jar that needs to be indexed + * @param pathToIndexFile The full path to the index file that needs to be generated + * @throws IOException if the jar is not found or could not write into the index file + * @since 3.8 + */ + public static void generateIndexForJar(String pathToJar, String pathToIndexFile) throws IOException { + new DefaultJavaIndexer().generateIndexForJar(pathToJar, pathToIndexFile); + } + +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java new file mode 100644 index 0000000..8959bfb --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2011 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 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.index; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; + +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.osgi.util.NLS; + +/** + * Implements an Eclipse Application for {@link org.eclipse.jdt.core.index.JavaIndexer}. + * + *+ * On MacOS, when invoked using the Eclipse executable, the "user.dir" property is set to the folder in which the + * eclipse.ini file is located. This makes it harder to use relative paths to point to the files to be jar'd or to + * the index file that is generated. + *
+ * + * + * @since 3.8 + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + */ +public class JavaIndexerApplication implements IApplication { + + private final static class Messages extends NLS { + private static final String MESSAGES_NAME = "org.eclipse.jdt.core.index.messages";//$NON-NLS-1$ + + public static String CommandLineProcessing; + public static String CommandLineUsage; + public static String CommandLineOnlyOneOutputError; + public static String CommandLineOutputTakesArgs; + public static String CommandLineOnlyOneJarError; + public static String CommandLineJarNotSpecified; + public static String CommandLineIndexFileNotSpecified; + public static String CaughtException; + public static String CommandLineJarFileNotExist; + + static { + NLS.initializeMessages(MESSAGES_NAME, Messages.class); + } + + public static String bind(String message) { + return bind(message, null); + } + + public static String bind(String message, Object binding) { + return bind(message, new Object[] { binding }); + } + + public static String bind(String message, Object binding1, Object binding2) { + return bind(message, new Object[] { binding1, binding2 }); + } + + public static String bind(String message, Object[] bindings) { + return MessageFormat.format(message, bindings); + } + } + + private String jarToIndex; + private String indexFile; + private boolean verbose = false; + private static final String PDE_LAUNCH = "-pdelaunch"; //$NON-NLS-1$ + private static final String ARG_HELP = "-help"; //$NON-NLS-1$ + private static final String ARG_VERBOSE = "-verbose"; //$NON-NLS-1$ + private static final String ARG_OUTPUT = "-output"; //$NON-NLS-1$ + + private void displayHelp() { + System.out.println(Messages.bind(Messages.CommandLineUsage)); + } + + private void displayError(String message) { + System.out.println(message); + System.out.println(); + displayHelp(); + } + + private boolean processCommandLine(String[] argsArray) { + ArrayList args = new ArrayList(); + for (int i = 0, max = argsArray.length; i < max; i++) { + args.add(argsArray[i]); + } + int index = 0; + final int argCount = argsArray.length; + + loop: while (index < argCount) { + String currentArg = argsArray[index++]; + if (PDE_LAUNCH.equals(currentArg)) { + continue loop; + } else if (ARG_HELP.equals(currentArg)) { + displayHelp(); + return false; + } else if (ARG_VERBOSE.equals(currentArg)) { + this.verbose = true; + continue loop; + } else if (ARG_OUTPUT.equals(currentArg)) { + if (this.indexFile != null) { + displayError(Messages.bind(Messages.CommandLineOnlyOneOutputError)); + return false; + } else if (index == argCount) { + displayError(Messages.bind(Messages.CommandLineOutputTakesArgs)); + return false; + } + this.indexFile = argsArray[index++]; + } else { + if (this.jarToIndex != null) { + displayError(Messages.bind(Messages.CommandLineOnlyOneJarError)); + return false; + } + this.jarToIndex = currentArg; + } + } + return true; + } + + public Object start(IApplicationContext context) throws Exception { + boolean execute = processCommandLine((String[]) context.getArguments().get(IApplicationContext.APPLICATION_ARGS)); + if (execute) { + if (this.jarToIndex != null && this.indexFile != null) { + File f = new File(this.jarToIndex); + if (f.exists()) { + if (this.verbose) { + System.out.println(Messages.bind(Messages.CommandLineProcessing, this.indexFile, this.jarToIndex)); + } + try { + JavaIndexer.generateIndexForJar(this.jarToIndex, this.indexFile); + } catch (IOException e) { + System.out.println(Messages.bind(Messages.CaughtException, "IOException", e.getLocalizedMessage())); //$NON-NLS-1$ + } + } else { + System.out.println(Messages.bind(Messages.CommandLineJarFileNotExist, this.jarToIndex)); + } + } else if (this.jarToIndex == null) { + System.out.println(Messages.bind(Messages.CommandLineJarNotSpecified)); + } else if (this.indexFile == null) { + System.out.println(Messages.bind(Messages.CommandLineIndexFileNotSpecified)); + } + } + return IApplication.EXIT_OK; + } + + public void stop() { + // do nothing + } + +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/messages.properties b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/messages.properties new file mode 100644 index 0000000..7b966bf --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/messages.properties @@ -0,0 +1,29 @@ +############################################################################### +# Copyright (c) 2000, 2006 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 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +CommandLineUsage=Usage: eclipse -application org.eclipse.jdt.core.JavaIndexerApplication [ OPTIONS ] -output