diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchScopeTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchScopeTests.java index deb70fd..52af315 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchScopeTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchScopeTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 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 @@ -1025,7 +1025,7 @@ // Index the output location as it is a library for the project IndexManager indexManager = JavaModelManager.getIndexManager(); - indexManager.indexLibrary(new Path("/P1/bin"), project.getProject()); + indexManager.indexLibrary(new Path("/P1/bin"), project.getProject(), null); waitUntilIndexesReady(); // Search for all types diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF index bb3c0af..354c648 100644 --- a/org.eclipse.jdt.core/META-INF/MANIFEST.MF +++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ org.eclipse.jdt.core.jdom, org.eclipse.jdt.core.search, org.eclipse.jdt.core.util, + org.eclipse.jdt.core.index, org.eclipse.jdt.internal.codeassist;x-internal:=true, org.eclipse.jdt.internal.codeassist.complete;x-internal:=true, org.eclipse.jdt.internal.codeassist.impl;x-internal:=true, 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..220f397 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.

+ * + * @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/core/IJavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java index bc17b09..b52c5ef 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaElementDelta.java @@ -57,6 +57,12 @@ *
  • {@link #F_SOURCEDETACHED} - The source attachment path or the source attachment root path * of a classpath entry corresponding to the element was removed. This flag is only valid if the element is an * {@link IPackageFragmentRoot}.
  • + *
  • {@link #F_INDEXATTACHED} - The index path or the index root path + * of a classpath entry corresponding to the element was added. This flag is only valid if the element is an + * {@link IPackageFragmentRoot}.
  • + *
  • {@link #F_INDEXDETACHED} - The index path or the index root path + * of a classpath entry corresponding to the element was removed. This flag is only valid if the element is an + * {@link IPackageFragmentRoot}.
  • *
  • {@link #F_SUPER_TYPES} - One of the supertypes of an {@link IType} has changed
  • . * * @@ -312,6 +318,26 @@ * @since 3.4 */ public int F_ANNOTATIONS = 0x400000; + + /** + * TODO SATYAM: We probably don't need this delta.. + * + * Change flag indicating that the index file of a classpath entry + * corresponding to the element was added. This flag is only valid if the element is an + * {@link IPackageFragmentRoot}. + * + * @since 3.8 + */ + public int F_INDEXATTACHED = 0x800000; + + /** + * Change flag indicating that the index file of a classpath entry + * corresponding to the element was removed. This flag is only valid if the element is an + * {@link IPackageFragmentRoot}. + * + * @since 3.8 + */ + public int F_INDEXDETACHED = 0x1000000; /** * Returns deltas for the children that have been added. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java index c1ed588..421ae4b 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java @@ -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 @@ -18,6 +18,7 @@ *******************************************************************************/ package org.eclipse.jdt.core; +import java.net.URL; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; @@ -243,6 +244,18 @@ */ void delete(int updateResourceFlags, int updateModelFlags, IProgressMonitor monitor) throws JavaModelException; /** + * Returns the URL to the index file attached to this package fragment root's binary archive. + * + * @return the URL to the corresponding index file, + * or null if this package fragment root's binary archive + * has no corresponding index file, or if this package fragment root + * is not a binary archive + * @exception JavaModelException if this operation fails + * + * @since 3.8 + */ + URL getIndexPath() throws JavaModelException; + /** * Returns this package fragment root's kind encoded as an integer. * A package fragment root can contain source files (i.e. files with one * of the {@link JavaCore#getJavaLikeExtensions() Java-like extensions}, 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..df8fbfa 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; @@ -362,12 +363,15 @@ } // check source attachment + // TODO SATYAM: Understand this IPath newSourcePath = newResolvedClasspath[index].getSourceAttachmentPath(); int sourceAttachmentFlags = getSourceAttachmentDeltaFlag(this.oldResolvedClasspath[i].getSourceAttachmentPath(), newSourcePath); IPath oldRootPath = this.oldResolvedClasspath[i].getSourceAttachmentRootPath(); IPath newRootPath = newResolvedClasspath[index].getSourceAttachmentRootPath(); int sourceAttachmentRootFlags = getSourceAttachmentDeltaFlag(oldRootPath, newRootPath); - int flags = sourceAttachmentFlags | sourceAttachmentRootFlags; + URL newIndexPath = ((ClasspathEntry)newResolvedClasspath[index]).getLibraryIndexLocation(); + int indexFlags = getIndexDeltaFlag(((ClasspathEntry)this.oldResolvedClasspath[i]).getLibraryIndexLocation(), newIndexPath); + int flags = sourceAttachmentFlags | sourceAttachmentRootFlags | indexFlags; if (flags != 0) { addClasspathDeltas(delta, this.project.computePackageFragmentRoots(this.oldResolvedClasspath[i]), flags); } else { @@ -432,6 +436,25 @@ } return result; + } + + /* + * TODO SATYAM: Put a comment + */ + private int getIndexDeltaFlag(URL oldPath, URL newPath) { + if (oldPath == null) { + if (newPath != null) { + return IJavaElementDelta.F_INDEXATTACHED; + } else { + return 0; + } + } else if (newPath == null) { + return IJavaElementDelta.F_INDEXDETACHED; + } else if (!oldPath.equals(newPath)) { + return IJavaElementDelta.F_INDEXATTACHED | IJavaElementDelta.F_INDEXDETACHED; + } else { + return 0; + } } /* @@ -511,7 +534,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; @@ -524,14 +547,23 @@ boolean pathHasChanged = true; IPath newPath = newResolvedClasspath[i].getPath(); for (int j = 0; j < oldLength; j++) { + //TODO SATYAM: Isn't index == j? IClasspathEntry oldEntry = this.oldResolvedClasspath[j]; if (oldEntry.getPath().equals(newPath)) { - pathHasChanged = false; + URL oldurl = ((ClasspathEntry)oldEntry).getLibraryIndexLocation(); + URL newurl = ((ClasspathEntry)newResolvedClasspath[i]).getLibraryIndexLocation(); + if (oldurl == null && newurl == null) { + pathHasChanged = false; + } else if (oldurl != null && newurl != null) { + pathHasChanged = !(newurl.equals(oldurl)); + } else if (oldurl != null) { + indexManager.removeIndex(newPath); + } break; } } if (pathHasChanged) { - indexManager.indexLibrary(newPath, this.project.getProject()); + indexManager.indexLibrary(newPath, this.project.getProject(),((ClasspathEntry)newResolvedClasspath[i]).getLibraryIndexLocation()); } 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 d8086ff..567ec4a 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 @@ -16,6 +16,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; @@ -2164,4 +2166,31 @@ } return JavaModelStatus.VERIFIED_OK; } + + /* + * 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; + } + + 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; + } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java index 6f94386..f93b992 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 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 @@ -18,6 +18,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.net.URL; import java.util.*; import org.eclipse.core.resources.*; @@ -75,6 +76,9 @@ /* A table from IPath (a source attachment path from a classpath entry) to IPath (a root path) */ public HashMap sourceAttachments = new HashMap(); + /* TODO SATYAM: Is this necessary?*/ + public HashMap indexMap = new HashMap(); + /* A table from IJavaProject to IJavaProject[] (the list of direct dependent of the key) */ public HashMap projectDependencies = new HashMap(); @@ -262,6 +266,7 @@ this.otherRoots = rootInfos[1]; this.sourceAttachments = rootInfos[2]; this.projectDependencies = rootInfos[3]; + this.indexMap = rootInfos[4]; this.rootsAreStale = false; } } @@ -274,6 +279,7 @@ this.otherRoots = rootInfos[1]; this.sourceAttachments = rootInfos[2]; this.projectDependencies = rootInfos[3]; + this.indexMap = rootInfos[4]; this.rootsAreStale = false; } } @@ -283,6 +289,7 @@ HashMap newOtherRoots = new HashMap(); HashMap newSourceAttachments = new HashMap(); HashMap newProjectDependencies = new HashMap(); + HashMap newIndexes = new HashMap(); IJavaModel model = JavaModelManager.getJavaModelManager().getJavaModel(); IJavaProject[] projects; @@ -354,9 +361,15 @@ if (sourceAttachmentPath != null) { newSourceAttachments.put(sourceAttachmentPath, path); } + + //TODO SATYAM: Do we need something like this? + URL url = ((ClasspathEntry)entry).getLibraryIndexLocation(); + if (url != null) { + newIndexes.put(url, path); + } } } - return new HashMap[] {newRoots, newOtherRoots, newSourceAttachments, newProjectDependencies}; + return new HashMap[] {newRoots, newOtherRoots, newSourceAttachments, newProjectDependencies, newIndexes}; } public synchronized ClasspathValidation[] removeClasspathValidations() { 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 f7a0c1c..2c65200 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 @@ -590,6 +590,38 @@ } } } + private void checkIndexChange(IResourceDelta delta, IResource res) { + IPath rootPath = (IPath)this.state.indexMap.get(externalPath(res)); + if (rootPath != null) { + RootInfo rootInfo = rootInfo(rootPath, delta.getKind()); + if (rootInfo != null) { + IJavaProject projectOfRoot = rootInfo.project; + IPackageFragmentRoot root = null; + try { + // close the root so that source attachment cache is flushed + root = projectOfRoot.findPackageFragmentRoot(rootPath); + if (root != null) { + root.close(); + } + } catch (JavaModelException e) { + // root doesn't exist: ignore + } + if (root == null) return; + switch (delta.getKind()) { + case IResourceDelta.ADDED: + currentDelta().indexAttached(root); + break; + case IResourceDelta.CHANGED: + currentDelta().indexDetached(root); + currentDelta().indexAttached(root); + break; + case IResourceDelta.REMOVED: + currentDelta().indexDetached(root); + break; + } + } + } + } /* * Closes the given element, which removes it from the cache of open elements. */ @@ -996,7 +1028,7 @@ // 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 { externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED); } @@ -1008,7 +1040,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 @@ -2239,6 +2271,7 @@ // check source attachment change checkSourceAttachmentChange(child, childRes); + checkIndexChange(child, childRes); // find out whether the child is a package fragment root of the current project IPath childPath = externalPath(childRes); @@ -2628,13 +2661,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/JavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java index ee0d715..e55c951 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java @@ -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 @@ -569,6 +569,29 @@ detachedDelta.changed(F_SOURCEDETACHED); insertDeltaTree(element, detachedDelta); } + +/** + * Creates the nested deltas resulting from a change operation. + * Convenience method for creating change deltas. + * The constructor should be used to create the root delta + * and then a change operation should call this method. + */ +public void indexAttached(IJavaElement element) { + JavaElementDelta attachedDelta = new JavaElementDelta(element); + attachedDelta.changed(F_INDEXATTACHED); + insertDeltaTree(element, attachedDelta); +} +/** + * Creates the nested deltas resulting from a change operation. + * Convenience method for creating change deltas. + * The constructor should be used to create the root delta + * and then a change operation should call this method. + */ +public void indexDetached(IJavaElement element) { + JavaElementDelta detachedDelta = new JavaElementDelta(element); + detachedDelta.changed(F_INDEXDETACHED); + insertDeltaTree(element, detachedDelta); +} /** * Returns a string representation of this delta's * structure suitable for debug purposes. 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 cdead40..6b7eb77 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 @@ -180,6 +180,8 @@ * Map from a package fragment root's path to a source attachment property (source path + ATTACHMENT_PROPERTY_DELIMITER + source root path) */ public Map rootPathToAttachments = new Hashtable(); + //TODO SATYAM: Is this necessary + public Map rootPathToIndexes = new Hashtable(); public final static String CP_VARIABLE_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$ public final static String CP_CONTAINER_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java index 9fb59c6..6aa31bd 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragmentRoot.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.jdt.internal.core; +import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Map; @@ -807,4 +808,19 @@ } } +public URL getIndexPath() { + try { + if (getKind() != K_BINARY) return null; + + IClasspathEntry entry = ((JavaProject) getParent()).getClasspathEntryFor(getPath()); + URL indexPath; + if (entry != null && (indexPath = ((ClasspathEntry)entry).getLibraryIndexLocation()) != null) + return indexPath; + + } 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 @@ + + + + + + + + + diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java new file mode 100644 index 0000000..3b7ef0f --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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.IOException; +import org.eclipse.jdt.internal.core.search.indexing.DefaultJavaIndexer; + +/** + * TODO SATYAM: Write a proper javadoc + * @since 3.8 + */ +public class JavaIndexer { + + /** + * TODO SATYAM: Write a javadoc + * @param pathToJar + * @param pathToIndexFile + * @throws IOException + */ + 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..4b5b931 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * 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 org.eclipse.jdt.core.JavaIndexer. + * + * TODO SATYAM: Improve the javadoc to include the arguments. + *

    + * 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 formatted or the + * configuration file to use to set the code formatter's options. + *

    + * + * + * @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 CommandLineOnlyOutputError; + 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.err.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 || index == argCount) { + displayError(Messages.bind(Messages.CommandLineOnlyOutputError)); + 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()) { + System.out.println(Messages.bind(Messages.CommandLineJarFileNotExist, this.jarToIndex)); + } + if (this.verbose) { + System.out.println(Messages.bind(Messages.CommandLineProcessing, this.jarToIndex, this.indexFile)); + } + try { + JavaIndexer.generateIndexForJar(this.jarToIndex, this.indexFile); + } catch (IOException e) { + System.out.println(Messages.bind(Messages.CaughtException, "IOException", e.getLocalizedMessage())); //$NON-NLS-1$ + } + } 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..704b29f --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/messages.properties @@ -0,0 +1,28 @@ +############################################################################### +# 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.JavaCodeGenerateIndex [ OPTIONS ] -output \n\ +\n\ +\ -output The index file to be generated.\n\ +\ +\ Jar file for which index needs to be generated.\n\ +\ +\n\ +\ OPTIONS:\n\ +\n\ +\ -help Display this message.\n\ +\ -verbose Be verbose about the job. +CommandLineProcessing=Generating index {1} for the jar {0}. +CommandLineOnlyOutputError=Only one output need to be specified. +CommandLineOnlyOneJarError=Only one jar file need to be specified. +CommandLineJarNotSpecified=No jar file is specified. +CommandLineIndexFileNotSpecified=No index file is specified. +CaughtException=Exception {0} - {1}. +CommandLineJarFileNotExist={0} does not exist. 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 168904f..d6fa5ed 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,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 @@ -13,6 +13,7 @@ import java.io.File; import java.io.IOException; import java.net.URI; +import java.net.URL; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -42,14 +43,17 @@ private static final char JAR_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.charAt(0); IFile resource; Scanner scanner; + private URL indexFile; - public AddJarFileToIndex(IFile resource, IndexManager manager) { + public AddJarFileToIndex(IFile resource, URL indexFile, IndexManager manager) { super(resource.getFullPath(), manager); this.resource = resource; + this.indexFile = indexFile; } - public AddJarFileToIndex(IPath jarPath, IndexManager manager) { + public AddJarFileToIndex(IPath jarPath, URL indexFile, IndexManager manager) { // external JAR scenario - no resource super(jarPath, manager); + this.indexFile = indexFile; } public boolean equals(Object o) { if (o instanceof AddJarFileToIndex) { @@ -71,6 +75,12 @@ if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true; + if (this.indexFile != null) { + //TODO SATYAM: Need to take care if the indexFile is in a jar. + boolean added = this.manager.addIndex(this.containerPath, new Path(this.indexFile.getFile())); + if (added) return true; + } + try { // if index is already cached, then do not perform any check // MUST reset the IndexManager if a jar file is changed diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java index 4313621..e68230b 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexAllProject.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 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 @@ -77,7 +77,7 @@ if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY && entry.getPath().equals(projectPath)) { // the project is also a library folder (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89815) // ensure a job exists to index it as a binary folder - this.manager.indexLibrary(projectPath, this.project); + this.manager.indexLibrary(projectPath, this.project, ((ClasspathEntry)entry).getLibraryIndexLocation()); return true; } } 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 f08c249..90d84e0 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,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 @@ -11,6 +11,7 @@ package org.eclipse.jdt.internal.core.search.indexing; import java.io.*; +import java.net.URL; import java.util.*; import java.util.zip.CRC32; @@ -53,12 +54,14 @@ // key = indexLocation path, value = index state integer private SimpleLookupTable indexStates = null; private File savedIndexNamesFile = new File(getSavedIndexesDirectory(), "savedIndexNames.txt"); //$NON-NLS-1$ + private File indexNamesMapFile = new File(getSavedIndexesDirectory(), "indexNamesMap.txt"); //$NON-NLS-1$ private File participantIndexNamesFile = new File(getSavedIndexesDirectory(), "participantsIndexNames.txt"); //$NON-NLS-1$ private boolean javaLikeNamesChanged = true; public static final Integer SAVED_STATE = new Integer(0); public static final Integer UPDATING_STATE = new Integer(1); public static final Integer UNKNOWN_STATE = new Integer(2); public static final Integer REBUILDING_STATE = new Integer(3); + public static final Integer REUSE_STATE = new Integer(4); // search participants who register indexes with the index manager private SimpleLookupTable participantsContainers = null; @@ -255,6 +258,15 @@ return index; } catch (IOException e) { // failed to read the existing file or its no longer compatible + if (currentIndexState == REUSE_STATE) { + // supposed to be in reuse state but error in the index file, so reindex. + if (VERBOSE) + Util.verbose("-> cannot reuse given index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ + this.indexLocations.put(containerPath, null); + indexLocation = computeIndexLocation(containerPath); + rebuildIndex(indexLocation, containerPath); + return null; + } if (currentIndexState != REBUILDING_STATE) { // rebuild index if existing file is corrupt, unless the index is already being rebuilt if (VERBOSE) Util.verbose("-> cannot reuse existing index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ @@ -268,6 +280,7 @@ rebuildIndex(indexLocation, containerPath); return null; } + //TODO SATYAM: should do something if in reuse state } // index wasn't found on disk, consider creating an empty new one if (createIfMissing) { @@ -315,7 +328,7 @@ IPath containerPath = (IPath) this.indexLocations.keyForValue(indexLocation); if (containerPath != null) {// sanity check index = getIndex(containerPath, indexLocation, true /*reuse index file*/, false /*do not create if none*/); - if (index != null && this.javaLikeNamesChanged && !index.isIndexForJar()) { + if (index != null && this.javaLikeNamesChanged && !index.isIndexForJar()) { //TODO SATYAM: shouldn't delete the pre-index files // When a change in java like names extension has been detected, all // non jar files indexes (i.e. containing sources) need to be rebuilt. // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=286379 @@ -387,6 +400,7 @@ this.javaLikeNamesChanged = false; deleteIndexFiles(); } + readIndexMap(indexesDirectoryPath.toOSString()); return this.indexStates; } private IPath getParticipantsContainer(IPath indexLocation) { @@ -474,7 +488,7 @@ for (int i = 0; i < entries.length; i++) { IClasspathEntry entry= entries[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) - indexLibrary(entry.getPath(), project); + indexLibrary(entry.getPath(), project, ((ClasspathEntry)entry).getLibraryIndexLocation()); } } catch(JavaModelException e){ // cannot retrieve classpath info } @@ -488,16 +502,15 @@ * Trigger addition of a library to an index * Note: the actual operation is performed in background */ -public void indexLibrary(IPath path, IProject requestingProject) { +public void indexLibrary(IPath path, IProject requestingProject, URL indexFile) { // requestingProject is no longer used to cancel jobs but leave it here just in case if (JavaCore.getPlugin() == null) return; - - Object target = JavaModel.getTarget(path, true); IndexRequest request = null; + Object target = JavaModel.getTarget(path, true); if (target instanceof IFile) { - request = new AddJarFileToIndex((IFile) target, this); + request = new AddJarFileToIndex((IFile) target, indexFile, this); } else if (target instanceof File) { - request = new AddJarFileToIndex(path, this); + request = new AddJarFileToIndex(path, indexFile, this); } else if (target instanceof IContainer) { request = new IndexBinaryFolder((IContainer) target, this); } else { @@ -508,6 +521,19 @@ if (!isJobWaiting(request)) request(request); } + +synchronized boolean addIndex(IPath containerPath, IPath indexFile) { + this.indexStates.put(indexFile, REUSE_STATE); + this.indexLocations.put(containerPath, indexFile); + Index index = getIndex(containerPath, indexFile, true, false); + if (index == null) { + this.indexLocations.put(containerPath, null); + return false; + } + writeIndexMapFile(); + return true; +} + /** * Index the content of the given source folder. */ @@ -584,9 +610,9 @@ } else if (target instanceof IFolder) { request = new IndexBinaryFolder((IFolder) target, this); } else if (target instanceof IFile) { - request = new AddJarFileToIndex((IFile) target, this); + request = new AddJarFileToIndex((IFile) target, null, this); } else if (target instanceof File) { - request = new AddJarFileToIndex(containerPath, this); + request = new AddJarFileToIndex(containerPath, null, this); } if (request != null) request(request); @@ -643,7 +669,9 @@ } if (indexFile == null) indexFile = new File(indexLocation.toOSString()); // index is not cached yet, but still want to delete the file - if (indexFile.exists()) { + if (this.indexStates.get(indexLocation) == REUSE_STATE) { + this.indexLocations.put(containerPath, null); + } else if (indexFile.exists()) { if (DEBUG) Util.verbose("removing index file " + indexFile); //$NON-NLS-1$ indexFile.delete(); @@ -673,7 +701,7 @@ locations = new IPath[max]; locations[count++] = indexLocation; File indexFile = index.getIndexFile(); - if (indexFile.exists()) { + if (indexFile.exists() && this.indexStates.get(indexLocation) != REUSE_STATE) { if (DEBUG) Util.verbose("removing index file " + indexFile); //$NON-NLS-1$ indexFile.delete(); @@ -894,6 +922,32 @@ } return null; } + +private char[][] readIndexMap(String dirOSString) { + try { + char[] indexMaps = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(this.indexNamesMapFile, null); + if (indexMaps.length > 0) { + char[][] names = CharOperation.splitOn('\n', indexMaps); + if (names.length >= 3) { + // First line is DiskIndex signature + saved plugin working location (see writeSavedIndexNamesFile()) + String savedSignature = DiskIndex.SIGNATURE + "+" + dirOSString; //$NON-NLS-1$ //TODO SATYAM Should dirOSString need to be stored + if (savedSignature.equals(new String(names[0]))) { + for (int i = 1, l = names.length-1 ; i < l ; i+=2) { + IPath indexPath = new Path(new String(names[i])); + this.indexLocations.put(new Path(new String(names[i+1])), indexPath ); + this.indexStates.put(indexPath, REUSE_STATE); + //TODO SATYAM: Is this good enough + } + } + + } + } + } catch (IOException ignored) { + if (VERBOSE) + Util.verbose("Failed to read saved index file names"); //$NON-NLS-1$ + } + return null; +} private void readParticipantsIndexNamesFile() { SimpleLookupTable containers = new SimpleLookupTable(3); try { @@ -947,6 +1001,7 @@ } writeSavedIndexNamesFile(); + writeIndexMapFile(); if (VERBOSE) { if (indexState == null) { @@ -1065,4 +1120,40 @@ } } } + +private void writeIndexMapFile() { + BufferedWriter writer = null; + try { + writer = new BufferedWriter(new FileWriter(this.indexNamesMapFile)); + writer.write(DiskIndex.SIGNATURE); + writer.write('+'); + writer.write(getJavaPluginWorkingLocation().toOSString()); + writer.write('\n'); + Object[] keys = this.indexStates.keyTable; + Object[] states = this.indexStates.valueTable; + for (int i = 0, l = states.length; i < l; i++) { + IPath key = (IPath) keys[i]; + if (key != null && !key.isEmpty() && states[i] == REUSE_STATE) { + IPath value = (IPath)this.indexLocations.keyForValue(key); + if (value != null) { + writer.write(key.toOSString()); + writer.write('\n'); + writer.write(value.toOSString()); + writer.write('\n'); + } + } + } + } catch (IOException ignored) { + if (VERBOSE) + Util.verbose("Failed to write saved index file names", System.err); //$NON-NLS-1$ + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + // ignore + } + } + } +} }