diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java index 8b41712..70415af 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/util/Util.java @@ -1348,6 +1348,34 @@ } } } + +/** + * Zips the given files into the given jar. All the files are kept at the root of the zip. + */ +public static void zipFiles(File[] files, String zipPath) throws IOException { + File zipFile = new File(zipPath); + if (zipFile.exists()) { + if (!delete(zipFile)) + throw new IOException("Could not delete " + zipPath); + // ensure the new zip file has a different timestamp than the previous one + int timeToWait = 1000; // some platform (like Linux) have a 1s granularity) + waitAtLeast(timeToWait); + } else { + zipFile.getParentFile().mkdirs(); + } + ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(zipFile)); + try { + for (int i = 0, length = files.length; i < length; i++) { + File file = files[i]; + ZipEntry entry = new ZipEntry(file.getName()); + zip.putNextEntry(entry); + zip.write(org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(file)); + zip.closeEntry(); + } + } finally { + zip.close(); + } +} /** * Returns the compilation errors / warnings for the given CompilationResult. * 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 c15475f..4ca9bdf 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 @@ -12,9 +12,11 @@ import java.io.File; import java.io.IOException; +import java.net.URL; import junit.framework.Test; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; @@ -28,6 +30,7 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.index.*; import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.tests.util.Util; import org.eclipse.jdt.internal.core.JavaModelManager; import org.eclipse.jdt.internal.core.UserLibraryClasspathContainer; import org.osgi.service.prefs.BackingStoreException; @@ -709,8 +712,8 @@ System.arraycopy(entries, 0, entries = new IClasspathEntry[length+1], 0, length); entries[length] = JavaCore.newContainerEntry(containerSuggestion.getPath()); p.setRawClasspath(entries, null); - } + public void testUserLibraryIndex() throws IOException, CoreException, BackingStoreException { String indexFilePath = getExternalResourcePath("Test.index"); String jarFilePath = getExternalResourcePath("Test.jar"); @@ -759,7 +762,102 @@ deleteProject("P"); new File(indexFilePath).delete(); new File(jarFilePath).delete(); + } + } + + // Test that it works if the index file is in the jar file + public void testIndexInJar() throws IOException, CoreException { + String indexFilePath = getExternalResourcePath("Test.index"); + String jarFilePath = getExternalResourcePath("Test.jar"); + String indexZipPath = getExternalResourcePath("TestIndex.zip"); + try { + createJar(new String[] { + "pkg/Test.java", + "package pkg;\n" + + "public class Test {\n" + + " protected Test(int i) {}\n" + + "}"}, jarFilePath); + + JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath); + Util.zipFiles(new File[]{new File(indexFilePath)}, indexZipPath); + + IJavaProject p = createJavaProject("P"); + Path libPath = new Path(jarFilePath); + String url = "jar:file:/"+indexZipPath+"!/Test.index"; + IClasspathAttribute attribute = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, url); + IClasspathEntry entry = JavaCore.newLibraryEntry(libPath, null, null, null, new IClasspathAttribute[]{attribute}, false); + setClasspath(p, new IClasspathEntry[] {entry}); + waitUntilIndexesReady(); + + assertEquals(url,JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexLocation().getUrl().toString()); + + 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(); + assertEquals(url,JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexLocation().getUrl().toString()); + search("Test", TYPE, DECLARATIONS, EXACT_RULE, SearchEngine.createJavaSearchScope(new IJavaElement[]{p})); + assertSearchResults(getExternalPath() + "Test.jar pkg.Test"); + } finally { + deleteProject("P"); + new File(indexZipPath).delete(); + new File(jarFilePath).delete(); } - + } + + // Test index file in platform + public void testPlatformJarIndexFile() throws CoreException, IOException { + String indexFilePath = null; + String jarFilePath = getExternalResourcePath("Test.jar"); + String indexUrl = "platform:/resource/ForIndex/Test.index.zip!/Test.index"; + try { + createJar(new String[] { + "pkg/Test.java", + "package pkg;\n" + + "public class Test {\n" + + " protected Test(int i) {}\n" + + "}"}, jarFilePath); + + IProject indexProj = createProject("ForIndex"); + indexFilePath = indexProj.getProject().getLocation().append("Test.index").toFile().getAbsolutePath(); + JavaIndexer.generateIndexForJar(jarFilePath, indexFilePath); + Util.zipFiles(new File[]{new File(indexFilePath)}, indexFilePath+".zip"); + + IJavaProject p = createJavaProject("P"); + 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"); + + URL url = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexLocation().getUrl(); + assertEquals(indexUrl, url.toString()); + + 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"); + + url = JavaModelManager.getIndexManager().getIndex(libPath, false, false).getIndexLocation().getUrl(); + assertEquals(indexUrl, url.toString()); + } finally { + deleteProject("P"); + if (indexFilePath != null) { + new File(indexFilePath).delete(); + new File(indexFilePath+".zip").delete(); + } + new File(jarFilePath).delete(); + deleteProject("ForIndex"); + } } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java index 4e3f6c4..2a87b52 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java @@ -14,6 +14,8 @@ import org.eclipse.core.runtime.*; import org.eclipse.jdt.internal.core.JavaModel; import org.eclipse.jdt.internal.core.JavaModelManager; +import org.eclipse.jdt.internal.core.index.FileIndexLocation; +import org.eclipse.jdt.internal.core.index.IndexLocation; import org.eclipse.jdt.internal.core.search.indexing.IndexManager; /** @@ -192,9 +194,9 @@ *

* * @param document the document to index - * @param indexLocation the location on the file system of the index + * @param indexPath the location on the file system of the index */ - public final void scheduleDocumentIndexing(SearchDocument document, IPath indexLocation) { + public final void scheduleDocumentIndexing(SearchDocument document, IPath indexPath) { IPath documentPath = new Path(document.getPath()); Object file = JavaModel.getTarget(documentPath, true); IPath containerPath = documentPath; @@ -205,11 +207,13 @@ } IndexManager manager = JavaModelManager.getIndexManager(); // TODO (frederic) should not have to create index manually, should expose API that recreates index instead + IndexLocation indexLocation; + indexLocation = new FileIndexLocation(indexPath.toFile(), true); manager.ensureIndexExists(indexLocation, containerPath); manager.scheduleDocumentIndexing(document, containerPath, indexLocation, this); - if (!indexLocation.equals(this.lastIndexLocation)) { - manager.updateParticipant(indexLocation, containerPath); - this.lastIndexLocation = indexLocation; + if (!indexPath.equals(this.lastIndexLocation)) { + manager.updateParticipant(indexPath, containerPath); + this.lastIndexLocation = indexPath; } } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java index 7644036..f4a3afd 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java @@ -23,7 +23,7 @@ public class DiskIndex { -File indexFile; +IndexLocation indexLocation; private int headerInfoOffset; private int numberOfChunks; @@ -82,12 +82,7 @@ } -DiskIndex(String fileName) { - if (fileName == null) - throw new java.lang.IllegalArgumentException(); - this.indexFile = new File(fileName); - - // clear cached items +DiskIndex() { this.headerInfoOffset = -1; this.numberOfChunks = -1; this.sizeOfLastChunk = -1; @@ -99,6 +94,13 @@ this.cachedCategoryName = null; this.categoryOffsets = null; this.categoryEnds = null; +} +DiskIndex(IndexLocation location) throws IOException { + this(); + if (location == null) { + throw new IllegalArgumentException(); + } + this.indexLocation = location; } SimpleSet addDocumentNames(String substring, MemoryIndex memoryIndex) throws IOException { // must skip over documents which have been added/changed/deleted in the memory index @@ -230,7 +232,7 @@ private void cacheDocumentNames() throws IOException { // will need all document names so get them now this.cachedChunks = new String[this.numberOfChunks][]; - FileInputStream stream = new FileInputStream(this.indexFile); + InputStream stream = this.indexLocation.getInputStream(); try { if (this.numberOfChunks > 5) BUFFER_READ_SIZE <<= 1; int offset = this.chunkOffsets[0]; @@ -370,9 +372,9 @@ } } void initialize(boolean reuseExistingFile) throws IOException { - if (this.indexFile.exists()) { + if (this.indexLocation.exists()) { if (reuseExistingFile) { - FileInputStream stream = new FileInputStream(this.indexFile); + InputStream stream = this.indexLocation.getInputStream(); this.streamBuffer = new byte[BUFFER_READ_SIZE]; this.bufferIndex = 0; this.bufferEnd = stream.read(this.streamBuffer, 0, 128); @@ -393,14 +395,14 @@ } return; } - if (!this.indexFile.delete()) { + if (!this.indexLocation.delete()) { if (DEBUG) - System.out.println("initialize - Failed to delete index " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Failed to delete index " + this.indexFile); //$NON-NLS-1$ + System.out.println("initialize - Failed to delete index " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Failed to delete index " + this.indexLocation); //$NON-NLS-1$ } } - if (this.indexFile.createNewFile()) { - FileOutputStream stream = new FileOutputStream(this.indexFile, false); + if (this.indexLocation.createNewFile()) { + FileOutputStream stream = new FileOutputStream(this.indexLocation.getIndexFile(), false); try { this.streamBuffer = new byte[BUFFER_READ_SIZE]; this.bufferIndex = 0; @@ -416,18 +418,18 @@ } } else { if (DEBUG) - System.out.println("initialize - Failed to create new index " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Failed to create new index " + this.indexFile); //$NON-NLS-1$ + System.out.println("initialize - Failed to create new index " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Failed to create new index " + this.indexLocation); //$NON-NLS-1$ } } private void initializeFrom(DiskIndex diskIndex, File newIndexFile) throws IOException { if (newIndexFile.exists() && !newIndexFile.delete()) { // delete the temporary index file if (DEBUG) - System.out.println("initializeFrom - Failed to delete temp index " + this.indexFile); //$NON-NLS-1$ + System.out.println("initializeFrom - Failed to delete temp index " + this.indexLocation); //$NON-NLS-1$ } else if (!newIndexFile.createNewFile()) { if (DEBUG) - System.out.println("initializeFrom - Failed to create temp index " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Failed to create temp index " + this.indexFile); //$NON-NLS-1$ + System.out.println("initializeFrom - Failed to create temp index " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Failed to create temp index " + this.indexLocation); //$NON-NLS-1$ } int size = diskIndex.categoryOffsets == null ? 8 : diskIndex.categoryOffsets.elementSize; @@ -500,6 +502,9 @@ DiskIndex mergeWith(MemoryIndex memoryIndex) throws IOException { // assume write lock is held // compute & write out new docNames + if (this.indexLocation == null) { + throw new IOException("Pre-built index file not writeable"); //$NON-NLS-1$ + } String[] docNames = readAllDocumentNames(); int previousLength = docNames.length; int[] positions = new int[previousLength]; // keeps track of the position of each document in the new sorted docNames @@ -509,15 +514,16 @@ if (previousLength == 0) return this; // nothing to do... memory index contained deleted documents that had never been saved // index is now empty since all the saved documents were removed - DiskIndex newDiskIndex = new DiskIndex(this.indexFile.getPath()); + DiskIndex newDiskIndex = new DiskIndex(this.indexLocation); newDiskIndex.initialize(false); return newDiskIndex; } - - DiskIndex newDiskIndex = new DiskIndex(this.indexFile.getPath() + ".tmp"); //$NON-NLS-1$ + File oldIndexFile = this.indexLocation.getIndexFile(); + DiskIndex newDiskIndex = new DiskIndex(new FileIndexLocation(new File(oldIndexFile.getPath() + ".tmp"))); //$NON-NLS-1$ + File newIndexFile = newDiskIndex.indexLocation.getIndexFile(); try { - newDiskIndex.initializeFrom(this, newDiskIndex.indexFile); - FileOutputStream stream = new FileOutputStream(newDiskIndex.indexFile, false); + newDiskIndex.initializeFrom(this, newIndexFile); + FileOutputStream stream = new FileOutputStream(newIndexFile, false); int offsetToHeader = -1; try { newDiskIndex.writeAllDocumentNames(docNames, stream); @@ -549,31 +555,31 @@ newDiskIndex.writeOffsetToHeader(offsetToHeader); // rename file by deleting previous index file & renaming temp one - if (this.indexFile.exists() && !this.indexFile.delete()) { + if (oldIndexFile.exists() && !oldIndexFile.delete()) { if (DEBUG) - System.out.println("mergeWith - Failed to delete " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Failed to delete index file " + this.indexFile); //$NON-NLS-1$ + System.out.println("mergeWith - Failed to delete " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Failed to delete index file " + this.indexLocation); //$NON-NLS-1$ } - if (!newDiskIndex.indexFile.renameTo(this.indexFile)) { + if (!newIndexFile.renameTo(oldIndexFile)) { if (DEBUG) - System.out.println("mergeWith - Failed to rename " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Failed to rename index file " + this.indexFile); //$NON-NLS-1$ + System.out.println("mergeWith - Failed to rename " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Failed to rename index file " + this.indexLocation); //$NON-NLS-1$ } } catch (IOException e) { - if (newDiskIndex.indexFile.exists() && !newDiskIndex.indexFile.delete()) + if (newIndexFile.exists() && !newIndexFile.delete()) if (DEBUG) - System.out.println("mergeWith - Failed to delete temp index " + newDiskIndex.indexFile); //$NON-NLS-1$ + System.out.println("mergeWith - Failed to delete temp index " + newDiskIndex.indexLocation); //$NON-NLS-1$ throw e; } - newDiskIndex.indexFile = this.indexFile; + newDiskIndex.indexLocation = this.indexLocation; return newDiskIndex; } private synchronized String[] readAllDocumentNames() throws IOException { if (this.numberOfChunks <= 0) return CharOperation.NO_STRINGS; - FileInputStream stream = new FileInputStream(this.indexFile); + InputStream stream = this.indexLocation.getInputStream(); try { int offset = this.chunkOffsets[0]; stream.skip(offset); @@ -612,7 +618,7 @@ } } - FileInputStream stream = new FileInputStream(this.indexFile); + InputStream stream = this.indexLocation.getInputStream(); HashtableOfObject categoryTable = null; char[][] matchingWords = null; int count = 0; @@ -626,7 +632,7 @@ try { if (size < 0) { // DEBUG System.err.println("-------------------- DEBUG --------------------"); //$NON-NLS-1$ - System.err.println("file = "+this.indexFile); //$NON-NLS-1$ + System.err.println("file = "+this.indexLocation); //$NON-NLS-1$ System.err.println("offset = "+offset); //$NON-NLS-1$ System.err.println("size = "+size); //$NON-NLS-1$ System.err.println("-------------------- END --------------------"); //$NON-NLS-1$ @@ -636,7 +642,7 @@ // DEBUG oom.printStackTrace(); System.err.println("-------------------- DEBUG --------------------"); //$NON-NLS-1$ - System.err.println("file = "+this.indexFile); //$NON-NLS-1$ + System.err.println("file = "+this.indexLocation); //$NON-NLS-1$ System.err.println("offset = "+offset); //$NON-NLS-1$ System.err.println("size = "+size); //$NON-NLS-1$ System.err.println("-------------------- END --------------------"); //$NON-NLS-1$ @@ -678,7 +684,7 @@ } if (matchingWords != null && count > 0) { - stream = new FileInputStream(this.indexFile); + stream = this.indexLocation.getInputStream(); try { stream.skip(firstOffset); this.bufferIndex = 0; @@ -696,7 +702,7 @@ this.streamBuffer = null; return categoryTable; } -private void readChunk(String[] docNames, FileInputStream stream, int index, int size) throws IOException { +private void readChunk(String[] docNames, InputStream stream, int index, int size) throws IOException { String current = new String(readStreamChars(stream)); docNames[index++] = current; for (int i = 1; i < size; i++) { @@ -734,7 +740,7 @@ throw new IllegalArgumentException(); this.streamBuffer = new byte[numberOfBytes]; this.bufferIndex = 0; - FileInputStream file = new FileInputStream(this.indexFile); + InputStream file = this.indexLocation.getInputStream(); try { file.skip(start); if (file.read(this.streamBuffer, 0, numberOfBytes) != numberOfBytes) @@ -763,7 +769,7 @@ if (arrayOffset instanceof int[]) return (int[]) arrayOffset; - FileInputStream stream = new FileInputStream(this.indexFile); + InputStream stream = this.indexLocation.getInputStream(); try { int offset = ((Integer) arrayOffset).intValue(); stream.skip(offset); @@ -776,19 +782,19 @@ this.streamBuffer = null; } } -private void readHeaderInfo(FileInputStream stream) throws IOException { +private void readHeaderInfo(InputStream stream) throws IOException { // must be same order as writeHeaderInfo() this.numberOfChunks = readStreamInt(stream); this.sizeOfLastChunk = this.streamBuffer[this.bufferIndex++] & 0xFF; this.documentReferenceSize = this.streamBuffer[this.bufferIndex++] & 0xFF; this.separator = (char) (this.streamBuffer[this.bufferIndex++] & 0xFF); - long fileLength = this.indexFile.length(); - if (this.numberOfChunks > fileLength ) { + long length = this.indexLocation.length(); + if (length != -1 && this.numberOfChunks > length) { // not an accurate check, but good enough https://bugs.eclipse.org/bugs/show_bug.cgi?id=350612 if (DEBUG) - System.out.println("Index file is corrupted " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Index file is corrupted " + this.indexFile); //$NON-NLS-1$ + System.out.println("Index file is corrupted " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Index file is corrupted " + this.indexLocation); //$NON-NLS-1$ } this.chunkOffsets = new int[this.numberOfChunks]; for (int i = 0; i < this.numberOfChunks; i++) @@ -799,11 +805,11 @@ int size = readStreamInt(stream); this.categoryOffsets = new HashtableOfIntValues(size); this.categoryEnds = new HashtableOfIntValues(size); - if (size > fileLength) { + if (length != -1 && size > length) { // not an accurate check, but good enough https://bugs.eclipse.org/bugs/show_bug.cgi?id=350612 if (DEBUG) - System.out.println("Index file is corrupted " + this.indexFile); //$NON-NLS-1$ - throw new IOException("Index file is corrupted " + this.indexFile); //$NON-NLS-1$ + System.out.println("Index file is corrupted " + this.indexLocation); //$NON-NLS-1$ + throw new IOException("Index file is corrupted " + this.indexLocation); //$NON-NLS-1$ } char[] previousCategory = null; int offset = -1; @@ -840,11 +846,13 @@ } } } -private void readStreamBuffer(FileInputStream stream) throws IOException { +private void readStreamBuffer(InputStream stream) throws IOException { // if we're about to read a known amount at the end of the existing buffer, but it does not completely fit // so we need to shift the remaining bytes to be read, and fill the buffer from the stream - if (this.bufferEnd < this.streamBuffer.length) - return; // we're at the end of the stream - nothing left to read + if (this.bufferEnd < this.streamBuffer.length) { + if (stream.available() == 0) + return; // we're at the end of the stream - nothing left to read + } int bytesInBuffer = this.bufferEnd - this.bufferIndex; if (bytesInBuffer > 0) @@ -872,7 +880,7 @@ * @exception UTFDataFormatException if the bytes do not represent a * valid UTF-8 encoding of a Unicode string. */ -private char[] readStreamChars(FileInputStream stream) throws IOException { +private char[] readStreamChars(InputStream stream) throws IOException { // read chars array length if (stream != null && this.bufferIndex + 2 >= this.bufferEnd) readStreamBuffer(stream); @@ -886,7 +894,7 @@ // how many characters can be decoded without refilling the buffer? int charsInBuffer = i + ((this.bufferEnd - this.bufferIndex) / 3); // all the characters must already be in the buffer if we're at the end of the stream - if (charsInBuffer > length || this.bufferEnd != this.streamBuffer.length || stream == null) + if (charsInBuffer > length || stream == null || (this.bufferEnd != this.streamBuffer.length && stream.available() == 0)) charsInBuffer = length; while (i < charsInBuffer) { byte b = this.streamBuffer[this.bufferIndex++]; @@ -931,7 +939,7 @@ } return word; } -private int[] readStreamDocumentArray(FileInputStream stream, int arraySize) throws IOException { +private int[] readStreamDocumentArray(InputStream stream, int arraySize) throws IOException { int[] indexes = new int[arraySize]; if (arraySize == 0) return indexes; @@ -972,7 +980,7 @@ } return indexes; } -private int readStreamInt(FileInputStream stream) throws IOException { +private int readStreamInt(InputStream stream) throws IOException { if (this.bufferIndex + 4 >= this.bufferEnd) { readStreamBuffer(stream); } @@ -1182,7 +1190,7 @@ } private void writeOffsetToHeader(int offsetToHeader) throws IOException { if (offsetToHeader > 0) { - RandomAccessFile file = new RandomAccessFile(this.indexFile, "rw"); //$NON-NLS-1$ + RandomAccessFile file = new RandomAccessFile(this.indexLocation.getIndexFile(), "rw"); //$NON-NLS-1$ try { file.seek(this.headerInfoOffset); // offset to position in header file.writeInt(offsetToHeader); diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java new file mode 100644 index 0000000..24cf485 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * 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.internal.core.index; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +public class FileIndexLocation extends IndexLocation { + File indexFile; + + public FileIndexLocation(File file) { + super(file); + this.indexFile = file; + } + + public FileIndexLocation(URL url, File file) { + super(url); + this.indexFile = file; + } + + public FileIndexLocation(File file, boolean participantIndex) { + this(file); + this.participantIndex = true; + } + + public boolean createNewFile() throws IOException { + return this.indexFile.createNewFile(); + } + + public boolean delete() { + return this.indexFile.delete(); + } + + public boolean equals(Object other) { + if (!(other instanceof FileIndexLocation)) return false; + return this.indexFile.equals(((FileIndexLocation) other).indexFile); + } + + public boolean exists() { + return this.indexFile.exists(); + } + + public String fileName() { + return this.indexFile.getName(); + } + + public File getIndexFile() { + return this.indexFile; + } + + InputStream getInputStream() throws IOException { + return new FileInputStream(this.indexFile); + } + + public String getCanonicalFilePath() { + try { + return this.indexFile.getCanonicalPath(); + } catch (IOException e) { + // ignore + } + return null; + } + + public int hashCode() { + return this.indexFile.hashCode(); + } + + public long lastModified() { + return this.indexFile.lastModified(); + } + + public long length() { + return this.indexFile.length(); + } + + public boolean startsWith(IPath path) { + try { + return path.isPrefixOf(new Path(this.indexFile.getCanonicalPath())); + } catch (IOException e) { + return false; + } + } + +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java index 3d32607..8caa73c 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.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 @@ -88,12 +88,12 @@ } -public Index(String fileName, String containerPath, boolean reuseExistingFile) throws IOException { +public Index(IndexLocation location, String containerPath, boolean reuseExistingFile) throws IOException { this.containerPath = containerPath; this.monitor = new ReadWriteMonitor(); this.memoryIndex = new MemoryIndex(); - this.diskIndex = new DiskIndex(fileName); + this.diskIndex = new DiskIndex(location); this.diskIndex.initialize(reuseExistingFile); if (reuseExistingFile) this.separator = this.diskIndex.separator; } @@ -110,7 +110,13 @@ return documentPath.substring(index + 1); } public File getIndexFile() { - return this.diskIndex == null ? null : this.diskIndex.indexFile; + return this.diskIndex == null ? null : this.diskIndex.indexLocation.getIndexFile(); +} +public IndexLocation getIndexLocation() { + return this.diskIndex == null ? null : this.diskIndex.indexLocation; +} +public long getIndexLastModified() { + return this.diskIndex == null? -1 : this.diskIndex.indexLocation.lastModified(); } public boolean hasChanged() { return this.memoryIndex.hasChanged(); @@ -180,7 +186,7 @@ */ public void reset() throws IOException { this.memoryIndex = new MemoryIndex(); - this.diskIndex = new DiskIndex(this.diskIndex.indexFile.getCanonicalPath()); + this.diskIndex = new DiskIndex(this.diskIndex.indexLocation); this.diskIndex.initialize(false/*do not reuse the index file*/); } public void save() throws IOException { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java new file mode 100644 index 0000000..3b49813 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * 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.internal.core.index; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IPath; + +/** + * The location of the index files are represented as {@link IndexLocation} + * + * This is an abstract class to allow different implementation for a jar entry and a file + * on the disk. Some of these functions could mean different for a jar entry or a file + * + */ +public abstract class IndexLocation { + + public static IndexLocation createIndexLocation(URL url) { + URL localUrl; + try { + localUrl = FileLocator.resolve(url); + } catch (IOException e) { + return null; + } + if (localUrl.getProtocol().equals("file")) { //$NON-NLS-1$ + return new FileIndexLocation(url, new File(localUrl.getPath())); + } + return new JarIndexLocation(url, localUrl); + } + + private final URL url; // url of the given index location + + /** + * Set to true if this index location is of an index file specified + * by a participant through + * {@link org.eclipse.jdt.core.search.SearchParticipant#scheduleDocumentIndexing} + */ + protected boolean participantIndex; + + protected IndexLocation(File file) { + URL tempUrl = null; + try { + tempUrl = file.toURI().toURL(); + } catch (MalformedURLException e) { + // should not happen + } + this.url = tempUrl; + } + + public IndexLocation(URL url) { + this.url = url; + } + + /** + * Closes any open streams. + */ + public void close() { + // default nothing to do + } + + /** + * Creates a new file for the given index location + * @return true if the file is created + * @throws IOException + */ + public abstract boolean createNewFile() throws IOException; + + public abstract boolean delete(); + + public abstract boolean exists(); + + public abstract String fileName(); + + /** + * @return the canonical file path if the location is a file or null otherwise + */ + public abstract String getCanonicalFilePath(); + + public abstract File getIndexFile(); + + abstract InputStream getInputStream() throws IOException; + + public URL getUrl() { + return this.url; + } + + public int hashCode() { + return this.url.hashCode(); + } + + public boolean isParticipantIndex() { + return this.participantIndex; + } + + /** + * @return the last modified time if the location is a file or -1 otherwise + */ + public abstract long lastModified(); + + /** + * @return the length of the file if the location is a file or -1 otherwise + */ + public abstract long length(); + + public abstract boolean startsWith(IPath path); + + public String toString() { + return this.url.toString(); + } +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/JarIndexLocation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/JarIndexLocation.java new file mode 100644 index 0000000..96c2da4 --- /dev/null +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/JarIndexLocation.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * 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.internal.core.index; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; + +public class JarIndexLocation extends IndexLocation { + private JarFile jarFile = null; + private JarEntry jarEntry = null; + private URL localUrl; + + public JarIndexLocation(URL url, URL localUrl2) { + super(url); + this.localUrl = localUrl2; + } + + public boolean createNewFile() throws IOException { + return false; + } + + public void close() { + if (this.jarFile != null) { + try { + this.jarFile.close(); + } catch (IOException e) { + // ignore + } + this.jarFile = null; + } + } + + public boolean delete() { + return false; + } + + public boolean equals(Object other) { + if (!(other instanceof JarIndexLocation)) return false; + return this.localUrl.equals(((JarIndexLocation) other).localUrl); + } + + public boolean exists() { + try { + if (this.jarFile == null) { + JarURLConnection connection = (JarURLConnection) this.localUrl.openConnection(); + JarFile file = connection.getJarFile(); + if (file == null) + return false; + file.close(); + } + } catch (IOException e) { + return false; + } + return true; + } + + public String fileName() { + return null; + } + + public File getIndexFile() { + return null; + } + + InputStream getInputStream() throws IOException { + if (this.jarFile == null) { + JarURLConnection connection = (JarURLConnection) this.localUrl.openConnection(); + this.jarFile = connection.getJarFile(); + this.jarEntry = connection.getJarEntry(); + } + if (this.jarFile == null || this.jarEntry == null) + return null; + return this.jarFile.getInputStream(this.jarEntry); + } + + public String getCanonicalFilePath() { + return null; + } + + public long lastModified() { + return -1; + } + + public long length() { + return -1; + } + + public boolean startsWith(IPath path) { + return (path.isPrefixOf(new Path(this.localUrl.getPath()))); + } + +} diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java index 4e584f2..20990c9 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java @@ -27,6 +27,7 @@ import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.builder.ReferenceCollection; import org.eclipse.jdt.internal.core.builder.State; +import org.eclipse.jdt.internal.core.index.IndexLocation; import org.eclipse.jdt.internal.core.search.indexing.IndexManager; import org.eclipse.jdt.internal.core.search.matching.MatchLocator; import org.eclipse.jdt.internal.core.search.matching.MethodPattern; @@ -38,7 +39,7 @@ public class IndexSelector { IJavaSearchScope searchScope; SearchPattern pattern; - IPath[] indexLocations; // cache of the keys for looking index up + IndexLocation[] indexLocations; // cache of the keys for looking index up public IndexSelector( IJavaSearchScope searchScope, @@ -267,10 +268,10 @@ } locations.remove(null); // Ensure no nulls - this.indexLocations = (IPath[]) locations.toArray(new IPath[locations.size()]); + this.indexLocations = (IndexLocation[]) locations.toArray(new IndexLocation[locations.size()]); } -public IPath[] getIndexLocations() { +public IndexLocation[] getIndexLocations() { if (this.indexLocations == null) { initializeIndexLocations(); } diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java index 13d6820..cf970b3 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.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 @@ -12,6 +12,7 @@ import org.eclipse.core.runtime.*; import org.eclipse.jdt.core.search.*; +import org.eclipse.jdt.internal.core.index.IndexLocation; import org.eclipse.jdt.internal.core.search.indexing.BinaryIndexer; import org.eclipse.jdt.internal.core.search.indexing.SourceIndexer; import org.eclipse.jdt.internal.core.search.matching.MatchLocator; @@ -98,7 +99,20 @@ * @see org.eclipse.jdt.core.search.SearchParticipant#selectIndexes(org.eclipse.jdt.core.search.SearchQuery, org.eclipse.jdt.core.search.SearchContext) */ public IPath[] selectIndexes(SearchPattern pattern, IJavaSearchScope scope) { + IndexSelector selector = (IndexSelector) this.indexSelector.get(); + if (selector == null) { + selector = new IndexSelector(scope, pattern); + this.indexSelector.set(selector); + } + IndexLocation[] urls = selector.getIndexLocations(); + IPath[] paths = new IPath[urls.length]; + for (int i = 0; i < urls.length; i++) { + paths[i] = new Path(urls[i].getIndexFile().getPath()); + } + return paths; + } + public IndexLocation[] selectIndexURLs(SearchPattern pattern, IJavaSearchScope scope) { IndexSelector selector = (IndexSelector) this.indexSelector.get(); if (selector == null) { selector = new IndexSelector(scope, pattern); diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java index 459730c..c83c2f1 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/PatternSearchJob.java @@ -17,7 +17,9 @@ import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jdt.core.search.*; import org.eclipse.jdt.internal.core.JavaModelManager; +import org.eclipse.jdt.internal.core.index.FileIndexLocation; import org.eclipse.jdt.internal.core.index.Index; +import org.eclipse.jdt.internal.core.index.IndexLocation; import org.eclipse.jdt.internal.core.search.indexing.ReadWriteMonitor; import org.eclipse.jdt.internal.core.search.matching.MatchLocator; import org.eclipse.jdt.internal.core.search.processing.IJob; @@ -76,8 +78,19 @@ } public Index[] getIndexes(IProgressMonitor progressMonitor) { // acquire the in-memory indexes on the fly - IPath[] indexLocations = this.participant.selectIndexes(this.pattern, this.scope); - int length = indexLocations.length; + IndexLocation[] indexLocations; + int length; + if (this.participant instanceof JavaSearchParticipant) { + indexLocations = ((JavaSearchParticipant)this.participant).selectIndexURLs(this.pattern, this.scope); + length = indexLocations.length; + } else { + IPath[] paths = this.participant.selectIndexes(this.pattern, this.scope); + length = paths.length; + indexLocations = new IndexLocation[paths.length]; + for (int i = 0, len = paths.length; i < len; i++) { + indexLocations[i] = new FileIndexLocation(paths[i].toFile(), true); + } + } Index[] indexes = JavaModelManager.getIndexManager().getIndexes(indexLocations, progressMonitor); this.areIndexesReady = indexes.length == length; return indexes; 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 2a98d01..812c462 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 @@ -34,6 +34,7 @@ import org.eclipse.jdt.internal.compiler.util.Util; import org.eclipse.jdt.internal.core.JavaModelManager; import org.eclipse.jdt.internal.core.index.Index; +import org.eclipse.jdt.internal.core.index.IndexLocation; import org.eclipse.jdt.internal.core.search.JavaSearchDocument; import org.eclipse.jdt.internal.core.search.processing.JobManager; @@ -42,14 +43,14 @@ private static final char JAR_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.charAt(0); IFile resource; Scanner scanner; - private IPath indexFileURL; + private IndexLocation indexFileURL; - public AddJarFileToIndex(IFile resource, IPath indexFile, IndexManager manager) { + public AddJarFileToIndex(IFile resource, IndexLocation indexFile, IndexManager manager) { super(resource.getFullPath(), manager); this.resource = resource; this.indexFileURL = indexFile; } - public AddJarFileToIndex(IPath jarPath, IPath indexFile, IndexManager manager) { + public AddJarFileToIndex(IPath jarPath, IndexLocation indexFile, IndexManager manager) { // external JAR scenario - no resource super(jarPath, manager); this.indexFileURL = indexFile; @@ -201,7 +202,11 @@ return false; } index.separator = JAR_SEPARATOR; - IPath indexPath = this.manager.computeIndexLocation(this.containerPath); + IPath indexPath = null; + IndexLocation indexLocation; + if ((indexLocation = index.getIndexLocation()) != null) { + indexPath = new Path(indexLocation.getCanonicalFilePath()); + } for (Enumeration e = zip.entries(); e.hasMoreElements();) { if (this.isCancelled) { if (JobManager.VERBOSE) diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java index 54b4fa4..cefcb0f 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java @@ -22,7 +22,9 @@ import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.internal.compiler.util.Util; +import org.eclipse.jdt.internal.core.index.FileIndexLocation; import org.eclipse.jdt.internal.core.index.Index; +import org.eclipse.jdt.internal.core.index.IndexLocation; import org.eclipse.jdt.internal.core.search.JavaSearchDocument; public class DefaultJavaIndexer { @@ -33,7 +35,8 @@ if (!f.exists()) { throw new FileNotFoundException(pathToJar + " not found"); //$NON-NLS-1$ } - Index index = new Index(pathToIndexFile, pathToJar, false /*reuse index file*/); + IndexLocation indexLocation = new FileIndexLocation(new File(pathToIndexFile)); + Index index = new Index(indexLocation, pathToJar, false /*reuse index file*/); SearchParticipant participant = SearchEngine.getDefaultSearchParticipant(); index.separator = JAR_SEPARATOR; ZipFile zip = new ZipFile(pathToJar); 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 e68230b..96aa904 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 @@ -107,7 +107,7 @@ for (int i = 0; i < max; i++) indexedFileNames.put(paths[i], DELETED); } - final long indexLastModified = max == 0 ? 0L : index.getIndexFile().lastModified(); + final long indexLastModified = max == 0 ? 0L : index.getIndexLastModified(); IWorkspaceRoot root = this.project.getWorkspace().getRoot(); for (int i = 0; i < sourceEntriesNumber; i++) { diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java index 7bb90f9..b06e0df 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexBinaryFolder.java @@ -80,7 +80,7 @@ for (int i = 0; i < max; i++) { indexedFileNames.put(paths[i], DELETED); } - final long indexLastModified = index.getIndexFile().lastModified(); + final long indexLastModified = index.getIndexLastModified(); this.folder.accept( new IResourceProxyVisitor() { public boolean visit(IResourceProxy proxy) throws CoreException { 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 2ab3653..75f441f 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 @@ -16,7 +16,6 @@ import java.util.zip.CRC32; import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; @@ -73,7 +72,7 @@ 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 - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); Object state = getIndexStates().get(indexLocation); Integer currentIndexState = state == null ? UNKNOWN_STATE : (Integer) state; if (currentIndexState.compareTo(REBUILDING_STATE) >= 0) return; // already rebuilding the index @@ -95,7 +94,7 @@ if (JavaCore.getPlugin() == null) return; SearchParticipant participant = SearchEngine.getDefaultSearchParticipant(); SearchDocument document = participant.getDocument(resource.getFullPath().toString()); - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); scheduleDocumentIndexing(document, containerPath, indexLocation, participant); } /** @@ -107,7 +106,7 @@ SearchParticipant participant = SearchEngine.getDefaultSearchParticipant(); SearchDocument document = participant.getDocument(resource.getFullPath().toString()); document.setParser(parser); - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); scheduleDocumentIndexing(document, containerPath, indexLocation, participant); } /* @@ -119,17 +118,17 @@ PatternSearchJob job = new PatternSearchJob(null, SearchEngine.getDefaultSearchParticipant(), scope, null); Index[] selectedIndexes = job.getIndexes(null); for (int i = 0, l = selectedIndexes.length; i < l; i++) { - String path = selectedIndexes[i].getIndexFile().getAbsolutePath(); - knownPaths.add(path); + IndexLocation IndexLocation = selectedIndexes[i].getIndexLocation(); + knownPaths.add(IndexLocation); } if (this.indexStates != null) { Object[] keys = this.indexStates.keyTable; - IPath[] locations = new IPath[this.indexStates.elementSize]; + IndexLocation[] locations = new IndexLocation[this.indexStates.elementSize]; int count = 0; for (int i = 0, l = keys.length; i < l; i++) { - IPath key = (IPath) keys[i]; - if (key != null && !knownPaths.includes(key.toOSString())) + IndexLocation key = (IndexLocation) keys[i]; + if (key != null && !knownPaths.includes(key)) locations[count++] = key; } if (count > 0) @@ -137,8 +136,8 @@ } deleteIndexFiles(knownPaths); } -public synchronized IPath computeIndexLocation(IPath containerPath) { - IPath indexLocation = (IPath) this.indexLocations.get(containerPath); +public synchronized IndexLocation computeIndexLocation(IPath containerPath) { + IndexLocation indexLocation = (IndexLocation) this.indexLocations.get(containerPath); if (indexLocation == null) { String pathString = containerPath.toOSString(); CRC32 checksumCalculator = new CRC32(); @@ -147,7 +146,7 @@ if (VERBOSE) Util.verbose("-> index name for " + pathString + " is " + fileName); //$NON-NLS-1$ //$NON-NLS-2$ // to share the indexLocation between the indexLocations and indexStates tables, get the key from the indexStates table - indexLocation = (IPath) getIndexStates().getKey(getJavaPluginWorkingLocation().append(fileName)); + indexLocation = (IndexLocation) getIndexStates().getKey(new FileIndexLocation(new File(getSavedIndexesDirectory(), fileName))); this.indexLocations.put(containerPath, indexLocation); } return indexLocation; @@ -164,7 +163,7 @@ for (int i = 0, l = indexesFiles.length; i < l; i++) { String fileName = indexesFiles[i].getAbsolutePath(); - if (pathsToKeep != null && pathsToKeep.includes(fileName)) continue; + if (pathsToKeep != null && pathsToKeep.includes(new FileIndexLocation(indexesFiles[i]))) continue; String suffix = ".index"; //$NON-NLS-1$ if (fileName.regionMatches(true, fileName.length() - suffix.length(), suffix, 0, suffix.length())) { if (VERBOSE || DEBUG) @@ -176,7 +175,7 @@ /* * Creates an empty index at the given location, for the given container path, if none exist. */ -public synchronized void ensureIndexExists(IPath indexLocation, IPath containerPath) { +public synchronized void ensureIndexExists(IndexLocation indexLocation, IPath containerPath) { SimpleLookupTable states = getIndexStates(); Object state = states.get(indexLocation); if (state == null) { @@ -210,7 +209,7 @@ * @param indexLocation The path of the index file * @return The corresponding index or null if not found */ -public synchronized Index getIndex(IPath indexLocation) { +public synchronized Index getIndex(IndexLocation indexLocation) { return (Index) this.indexes.get(indexLocation); // is null if unknown, call if the containerPath must be computed } /** @@ -222,7 +221,7 @@ * Warning: Does not check whether index is consistent (not being used) */ public synchronized Index getIndex(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) { - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing); } /** @@ -233,7 +232,7 @@ * * Warning: Does not check whether index is consistent (not being used) */ -public synchronized Index getIndex(IPath containerPath, IPath indexLocation, boolean reuseExistingFile, boolean createIfMissing) { +public synchronized Index getIndex(IPath containerPath, IndexLocation indexLocation, boolean reuseExistingFile, boolean createIfMissing) { // Path is already canonical per construction Index index = getIndex(indexLocation); if (index == null) { @@ -248,19 +247,17 @@ // index isn't cached, consider reusing an existing index file String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); - String indexLocationString = indexLocation.toOSString(); if (reuseExistingFile) { - File indexFile = new File(indexLocationString); - if (indexFile.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing + if (indexLocation.exists()) { // check before creating index so as to avoid creating a new empty index if file is missing try { - index = new Index(indexLocationString, containerPathString, true /*reuse index file*/); + index = new Index(indexLocation, containerPathString, true /*reuse index file*/); this.indexes.put(indexLocation, index); return index; } catch (IOException e) { // failed to read the existing file or its no longer compatible if (currentIndexState != REBUILDING_STATE && currentIndexState != REUSE_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$ + Util.verbose("-> cannot reuse existing index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ rebuildIndex(indexLocation, containerPath); return null; } @@ -285,13 +282,13 @@ if (createIfMissing) { try { if (VERBOSE) - Util.verbose("-> create empty index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ - index = new Index(indexLocationString, containerPathString, false /*do not reuse index file*/); + Util.verbose("-> create empty index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ + index = new Index(indexLocation, containerPathString, false /*do not reuse index file*/); this.indexes.put(indexLocation, index); return index; } catch (IOException e) { if (VERBOSE) - Util.verbose("-> unable to create empty index: "+indexLocationString+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ + Util.verbose("-> unable to create empty index: "+indexLocation+" path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ // The file could not be created. Possible reason: the project has been deleted. return null; } @@ -307,7 +304,7 @@ * @param locations The list of of the index files path * @return The corresponding indexes list. */ -public Index[] getIndexes(IPath[] locations, IProgressMonitor progressMonitor) { +public Index[] getIndexes(IndexLocation[] locations, IProgressMonitor progressMonitor) { // acquire the in-memory indexes on the fly int length = locations.length; Index[] locatedIndexes = new Index[length]; @@ -320,7 +317,7 @@ throw new OperationCanceledException(); } // may trigger some index recreation work - IPath indexLocation = locations[i]; + IndexLocation indexLocation = locations[i]; Index index = getIndex(indexLocation); if (index == null) { // only need containerPath if the index must be built @@ -342,18 +339,16 @@ index = null; } } else { - if (!getJavaPluginWorkingLocation().isPrefixOf(indexLocation)) { // the index belongs to non-jdt search participant - if (indexLocation.toFile().exists()) { - try { - IPath container = getParticipantsContainer(indexLocation); - if (container != null) { - index = new Index(indexLocation.toOSString(), container.toOSString(), true /*reuse index file*/); - this.indexes.put(indexLocation, index); - } - } catch (IOException e) { - // ignore + if (indexLocation.isParticipantIndex() && indexLocation.exists()) { // the index belongs to non-jdt search participant + try { + IPath container = getParticipantsContainer(indexLocation); + if (container != null) { + index = new Index(indexLocation, container.toOSString(), true /*reuse index file*/); + this.indexes.put(indexLocation, index); } - } + } catch (IOException e) { + // ignore + } } } } @@ -370,7 +365,7 @@ return locatedIndexes; } public synchronized Index getIndexForUpdate(IPath containerPath, boolean reuseExistingFile, boolean createIfMissing) { - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); if (getIndexStates().get(indexLocation) == REBUILDING_STATE) return getIndex(containerPath, indexLocation, reuseExistingFile, createIfMissing); @@ -380,13 +375,13 @@ if (this.indexStates != null) return this.indexStates; this.indexStates = new SimpleLookupTable(); - IPath indexesDirectoryPath = getJavaPluginWorkingLocation(); - char[][] savedNames = readIndexState(indexesDirectoryPath.toOSString()); + File indexesDirectoryPath = getSavedIndexesDirectory(); + char[][] savedNames = readIndexState(getJavaPluginWorkingLocation().toOSString()); if (savedNames != null) { for (int i = 1, l = savedNames.length; i < l; i++) { // first name is saved signature, see readIndexState() char[] savedName = savedNames[i]; if (savedName.length > 0) { - IPath indexLocation = indexesDirectoryPath.append(new String(savedName)); // shares indexesDirectoryPath's segments + IndexLocation indexLocation = new FileIndexLocation(new File(indexesDirectoryPath, String.valueOf(savedName))); // shares indexesDirectoryPath's segments if (VERBOSE) Util.verbose("Reading saved index file " + indexLocation); //$NON-NLS-1$ this.indexStates.put(indexLocation, SAVED_STATE); @@ -401,7 +396,7 @@ } return this.indexStates; } -private IPath getParticipantsContainer(IPath indexLocation) { +private IPath getParticipantsContainer(IndexLocation indexLocation) { if (this.participantsContainers == null) { readParticipantsIndexNamesFile(); } @@ -502,15 +497,7 @@ */ public void indexLibrary(IPath path, IProject requestingProject, URL indexURL) { // requestingProject is no longer used to cancel jobs but leave it here just in case - IPath indexFile = null; - if (indexURL != null) { - try { - indexFile = new Path(FileLocator.resolve(indexURL).getPath()); - } catch (IOException e) { - if (VERBOSE) - Util.verbose("-> cannot resolve the url : "+ indexURL + " specified for " + path); //$NON-NLS-1$ //$NON-NLS-2$ - } - } + IndexLocation indexFile = indexURL != null ? IndexLocation.createIndexLocation(indexURL): null; if (JavaCore.getPlugin() == null) return; IndexRequest request = null; Object target = JavaModel.getTarget(path, true); @@ -529,11 +516,12 @@ request(request); } -synchronized boolean addIndex(IPath containerPath, IPath indexFile) { +synchronized boolean addIndex(IPath containerPath, IndexLocation indexFile) { this.indexStates.put(indexFile, REUSE_STATE); this.indexLocations.put(containerPath, indexFile); Index index = getIndex(containerPath, indexFile, true, false); if (index == null) { + indexFile.close(); this.indexLocations.put(containerPath, null); return false; } @@ -554,7 +542,7 @@ request(new AddFolderToIndex(sourceFolder, project, inclusionPatterns, exclusionPatterns, this)); } public synchronized void jobWasCancelled(IPath containerPath) { - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); Index index = getIndex(indexLocation); if (index != null) { index.monitor = null; @@ -600,7 +588,7 @@ } return null; } -private void rebuildIndex(IPath indexLocation, IPath containerPath) { +private void rebuildIndex(IndexLocation indexLocation, IPath containerPath) { Object target = JavaModel.getTarget(containerPath, true); if (target == null) return; @@ -633,13 +621,13 @@ String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); try { // Path is already canonical - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); Index index = getIndex(indexLocation); ReadWriteMonitor monitor = index == null ? null : index.monitor; if (VERBOSE) Util.verbose("-> recreating index: "+indexLocation+" for path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ - index = new Index(indexLocation.toOSString(), containerPathString, false /*do not reuse index file*/); + index = new Index(indexLocation, containerPathString, false /*do not reuse index file*/); this.indexes.put(indexLocation, index); index.monitor = monitor; return index; @@ -666,7 +654,7 @@ public synchronized void removeIndex(IPath containerPath) { if (VERBOSE || DEBUG) Util.verbose("removing index " + containerPath); //$NON-NLS-1$ - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); Index index = getIndex(indexLocation); File indexFile = null; if (index != null) { @@ -674,10 +662,11 @@ indexFile = index.getIndexFile(); } if (indexFile == null) - indexFile = new File(indexLocation.toOSString()); // index is not cached yet, but still want to delete the file + indexFile = indexLocation.getIndexFile(); // index is not cached yet, but still want to delete the file if (this.indexStates.get(indexLocation) == REUSE_STATE) { + indexLocation.close(); this.indexLocations.put(containerPath, null); - } else if (indexFile.exists()) { + } else if (indexFile != null && indexFile.exists()) { if (DEBUG) Util.verbose("removing index file " + indexFile); //$NON-NLS-1$ indexFile.delete(); @@ -693,24 +682,25 @@ Util.verbose("removing index path " + path); //$NON-NLS-1$ Object[] keyTable = this.indexes.keyTable; Object[] valueTable = this.indexes.valueTable; - IPath[] locations = null; + IndexLocation[] locations = null; int max = this.indexes.elementSize; int count = 0; for (int i = 0, l = keyTable.length; i < l; i++) { - IPath indexLocation = (IPath) keyTable[i]; + IndexLocation indexLocation = (IndexLocation) keyTable[i]; if (indexLocation == null) continue; - if (path.isPrefixOf(indexLocation)) { + if (indexLocation.startsWith(path)) { Index index = (Index) valueTable[i]; index.monitor = null; if (locations == null) - locations = new IPath[max]; + locations = new IndexLocation[max]; locations[count++] = indexLocation; - File indexFile = index.getIndexFile(); - if (indexFile.exists()) { + if (this.indexStates.get(indexLocation) == REUSE_STATE) { + indexLocation.close(); + } else { if (DEBUG) - Util.verbose("removing index file " + indexFile); //$NON-NLS-1$ - indexFile.delete(); + Util.verbose("removing index file " + indexLocation); //$NON-NLS-1$ + indexLocation.delete(); } } else { max--; @@ -786,7 +776,7 @@ String containerPathString = containerPath.getDevice() == null ? containerPath.toString() : containerPath.toOSString(); try { // Path is already canonical - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); Index index = getIndex(indexLocation); if (VERBOSE) { Util.verbose("-> reseting index: "+indexLocation+" for path: "+containerPathString); //$NON-NLS-1$ //$NON-NLS-2$ @@ -810,7 +800,7 @@ // must have permission to write from the write monitor if (index.hasChanged()) { if (VERBOSE) - Util.verbose("-> saving index " + index.getIndexFile()); //$NON-NLS-1$ + Util.verbose("-> saving index " + index.getIndexLocation()); //$NON-NLS-1$ index.save(); } synchronized (this) { @@ -822,7 +812,7 @@ if (((IndexRequest) job).containerPath.equals(containerPath)) return; } } - IPath indexLocation = computeIndexLocation(containerPath); + IndexLocation indexLocation = computeIndexLocation(containerPath); updateIndexState(indexLocation, SAVED_STATE); } } @@ -877,7 +867,7 @@ } this.needToSave = !allSaved; } -public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath container, final IPath indexLocation, final SearchParticipant searchParticipant) { +public void scheduleDocumentIndexing(final SearchDocument searchDocument, IPath container, final IndexLocation indexLocation, final SearchParticipant searchParticipant) { request(new IndexRequest(container, this) { public boolean execute(IProgressMonitor progressMonitor) { if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true; @@ -890,7 +880,7 @@ try { monitor.enterWrite(); // ask permission to write - indexDocument(searchDocument, searchParticipant, index, indexLocation); + indexDocument(searchDocument, searchParticipant, index, new Path(indexLocation.getCanonicalFilePath())); } finally { monitor.exitWrite(); // free write lock } @@ -944,7 +934,8 @@ // First line is DiskIndex signature (see writeParticipantsIndexNamesFile()) if (DiskIndex.SIGNATURE.equals(new String(names[0]))) { for (int i = 1, l = names.length-1 ; i < l ; i+=2) { - containers.put(new Path(new String(names[i])), new Path(new String(names[i+1]))); + IndexLocation indexLocation = new FileIndexLocation(new File(new String(names[i])), true); + containers.put(indexLocation, new Path(new String(names[i+1]))); } } } @@ -956,7 +947,7 @@ this.participantsContainers = containers; return; } -private synchronized void removeIndexesState(IPath[] locations) { +private synchronized void removeIndexesState(IndexLocation[] locations) { getIndexStates(); // ensure the states are initialized int length = locations.length; boolean changed = false; @@ -973,8 +964,8 @@ writeSavedIndexNamesFile(); } -private synchronized void updateIndexState(IPath indexLocation, Integer indexState) { - if (indexLocation.isEmpty()) +private synchronized void updateIndexState(IndexLocation indexLocation, Integer indexState) { + if (indexLocation == null) throw new IllegalArgumentException(); getIndexStates(); // ensure the states are initialized @@ -1002,10 +993,11 @@ } } -public void updateParticipant(IPath indexLocation, IPath containerPath) { +public void updateParticipant(IPath indexPath, IPath containerPath) { if (this.participantsContainers == null) { readParticipantsIndexNamesFile(); - } + } + IndexLocation indexLocation = new FileIndexLocation(indexPath.toFile(), true); if (this.participantsContainers.get(indexLocation) == null) { this.participantsContainers.put(indexLocation, containerPath); this.participantUpdated = true; @@ -1054,9 +1046,9 @@ Object[] indexFiles = this.participantsContainers.keyTable; Object[] containers = this.participantsContainers.valueTable; for (int i = 0, l = indexFiles.length; i < l; i++) { - IPath indexFile = (IPath)indexFiles[i]; + IndexLocation indexFile = (IndexLocation)indexFiles[i]; if (indexFile != null) { - writer.write(indexFile.toOSString()); + writer.write(indexFile.getIndexFile().getPath()); writer.write('\n'); writer.write(((IPath)containers[i]).toOSString()); writer.write('\n'); @@ -1086,9 +1078,9 @@ 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] == SAVED_STATE) { - writer.write(key.lastSegment()); + IndexLocation key = (IndexLocation) keys[i]; + if (key != null && states[i] == SAVED_STATE) { + writer.write(key.fileName()); writer.write('\n'); } }