Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 177941 Details for
Bug 323392
[index] IndexbinaryFolder removing JSP translations from index because their in memory CompliationUnits no longer exist
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
SSE/JSP Patch needed to reproduce the problem
323392_reproduce_patch.txt (text/plain), 142.91 KB, created by
Ian Tewksbury
on 2010-09-01 08:23:52 EDT
(
hide
)
Description:
SSE/JSP Patch needed to reproduce the problem
Filename:
MIME Type:
Creator:
Ian Tewksbury
Created:
2010-09-01 08:23:52 EDT
Size:
142.91 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.jst.jsp.core >Index: src/org/eclipse/jst/jsp/core/internal/JSPCoreMessages.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/JSPCoreMessages.java,v >retrieving revision 1.27 >diff -u -r1.27 JSPCoreMessages.java >--- src/org/eclipse/jst/jsp/core/internal/JSPCoreMessages.java 19 Mar 2010 20:18:09 -0000 1.27 >+++ src/org/eclipse/jst/jsp/core/internal/JSPCoreMessages.java 1 Sep 2010 12:23:07 -0000 >@@ -61,6 +61,9 @@ > public static String Initializing; > public static String Persisting_JSP_Translations; > >+ public static String JSPCorePlugin_Initializing_JSP_Tools; >+ public static String JSPIndexManager; >+ > /** > * @deprecated > */ >Index: src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java,v >retrieving revision 1.19.2.1 >diff -u -r1.19.2.1 JSPCorePlugin.java >--- src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java 23 Aug 2010 20:43:11 -0000 1.19.2.1 >+++ src/org/eclipse/jst/jsp/core/internal/JSPCorePlugin.java 1 Sep 2010 12:23:07 -0000 >@@ -10,9 +10,13 @@ > *******************************************************************************/ > package org.eclipse.jst.jsp.core.internal; > >+import org.eclipse.core.resources.IResourceChangeEvent; >+import org.eclipse.core.resources.IResourceChangeListener; > import org.eclipse.core.resources.ISaveContext; > import org.eclipse.core.resources.ISaveParticipant; > import org.eclipse.core.resources.ISavedState; >+import org.eclipse.core.resources.IWorkspace; >+import org.eclipse.core.resources.IWorkspaceRunnable; > import org.eclipse.core.resources.ResourcesPlugin; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IProgressMonitor; >@@ -24,7 +28,6 @@ > import org.eclipse.jst.jsp.core.internal.contentmodel.TaglibController; > import org.eclipse.jst.jsp.core.internal.contentproperties.JSPFContentPropertiesManager; > import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache; >-import org.eclipse.jst.jsp.core.internal.java.JSPTranslatorPersister; > import org.eclipse.jst.jsp.core.internal.java.search.JSPIndexManager; > import org.eclipse.jst.jsp.core.internal.taglib.TaglibHelperManager; > import org.eclipse.jst.jsp.core.taglib.TaglibIndex; >@@ -34,19 +37,22 @@ > * The main plugin class to be used in the desktop. > */ > public class JSPCorePlugin extends Plugin { >- // The shared instance. >+ /** singleton instance of the plugin */ > private static JSPCorePlugin plugin; >- >- /** Save participant for this plugin */ >- ISaveParticipant fSaveParticipant; > > /** >+ * <p>Job used to finish tasks needed to start up the plugin but that did not have >+ * to block the plugin start up process.</p> >+ */ >+ private Job fPluginInitializerJob; >+ >+ /** > * The constructor. > */ > public JSPCorePlugin() { > super(); > plugin = this; >- fSaveParticipant = new SaveParticipant(); >+ this.fPluginInitializerJob = new PluginInitializerJob(); > } > > /** >@@ -65,7 +71,7 @@ > super.start(context); > > /* >- * JSPIndexManager depends on TaglibController, so TaglibController >+ * JSPIndexManager_old depends on TaglibController, so TaglibController > * should be started first > */ > TaglibIndex.startup(); >@@ -73,37 +79,9 @@ > > // listen for classpath changes > JavaCore.addElementChangedListener(TaglibHelperManager.getInstance()); >- >- //restore save state and process any events that happened before plugin loaded >- if (JSPTranslatorPersister.ACTIVATED) { >- Job persister = new Job(JSPCoreMessages.Initializing) { >- protected IStatus run(IProgressMonitor monitor) { >- ISavedState savedState = null; >- try { >- savedState = ResourcesPlugin.getWorkspace().addSaveParticipant(plugin.getBundle().getSymbolicName(), fSaveParticipant); >- } >- catch (CoreException e) { >- Logger.logException("Could not load previous save state", e); >- } >- if (savedState != null) { >- try { >- Thread.currentThread().setPriority(Thread.MIN_PRIORITY); >- } >- finally { >- savedState.processResourceChangeEvents(JSPTranslatorPersister.getDefault()); >- } >- } >- return Status.OK_STATUS; >- } >- }; >- persister.setUser(false); >- persister.schedule(2000); >- // set up persister to listen to resource change events >- ResourcesPlugin.getWorkspace().addResourceChangeListener(JSPTranslatorPersister.getDefault()); >- } > >- //init the JSP index >- JSPIndexManager.getInstance().initialize(); >+ //schedule delayed initialization >+ this.fPluginInitializerJob.schedule(2000); > > // listen for resource changes to update content properties keys > JSPFContentPropertiesManager.startup(); >@@ -119,22 +97,14 @@ > public void stop(BundleContext context) throws Exception { > DeploymentDescriptorPropertyCache.stop(); > >- /* >- * stop listening for resource changes to update content properties >- * keys >- */ >+ // stop listening for resource changes to update content properties keys > JSPFContentPropertiesManager.shutdown(); > > //remove the plugin save participant > ResourcesPlugin.getWorkspace().removeSaveParticipant(plugin.getBundle().getSymbolicName()); > >- //remove the translator persister >- if(JSPTranslatorPersister.ACTIVATED) { >- ResourcesPlugin.getWorkspace().removeResourceChangeListener(JSPTranslatorPersister.getDefault()); >- } >- > // stop any indexing >- JSPIndexManager.getInstance().shutdown(); >+ JSPIndexManager.getDefault().stop(); > > // stop listening for classpath changes > JavaCore.removeElementChangedListener(TaglibHelperManager.getInstance()); >@@ -147,6 +117,72 @@ > } > > /** >+ * <p>A {@link Job} used to perform delayed initialization for the plugin</p> >+ */ >+ private static class PluginInitializerJob extends Job { >+ /** >+ * <p>Default constructor to set up this {@link Job} as a >+ * long running system {@link Job}</p> >+ */ >+ protected PluginInitializerJob() { >+ super(JSPCoreMessages.JSPCorePlugin_Initializing_JSP_Tools); >+ >+ this.setUser(false); >+ this.setSystem(true); >+ this.setPriority(Job.LONG); >+ } >+ >+ /** >+ * <p>Perform delayed initialization for the plugin</p> >+ * >+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) >+ */ >+ protected IStatus run(IProgressMonitor monitor) { >+ IStatus status = Status.OK_STATUS; >+ final IWorkspace workspace = ResourcesPlugin.getWorkspace(); >+ try { >+ workspace.run(new IWorkspaceRunnable() { >+ public void run(final IProgressMonitor worspaceMonitor) throws CoreException { >+ ISavedState savedState = null; >+ >+ try { >+ //add the save participant for this bundle >+ savedState = ResourcesPlugin.getWorkspace().addSaveParticipant( >+ JSPCorePlugin.plugin.getBundle().getSymbolicName(), new SaveParticipant()); >+ } catch (CoreException e) { >+ Logger.logException("JSP Core Plugin failed at loading previously saved state." + >+ " All componenets dependent on this state will start as if first workspace load.", e); >+ } >+ >+ //if there is a saved state start up using that, else start up cold >+ if(savedState != null) { >+ try { >+ Thread.currentThread().setPriority(Thread.MIN_PRIORITY); >+ } finally { >+ savedState.processResourceChangeEvents(new IResourceChangeListener() { >+ /** >+ * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) >+ */ >+ public void resourceChanged(IResourceChangeEvent event) { >+ JSPIndexManager.getDefault().start(event.getDelta(), worspaceMonitor); >+ } >+ }); >+ } >+ } else { >+ JSPIndexManager.getDefault().start(null, worspaceMonitor); >+ } >+ } >+ }, monitor); >+ } catch(CoreException e) { >+ status = e.getStatus(); >+ } >+ >+ return status; >+ } >+ >+ } >+ >+ /** > * Used so that all of the IResourceChangeEvents that occurred before > * this plugin loaded can be processed. > */ >Index: src/org/eclipse/jst/jsp/core/internal/JSPCorePluginResources.properties >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/JSPCorePluginResources.properties,v >retrieving revision 1.33 >diff -u -r1.33 JSPCorePluginResources.properties >--- src/org/eclipse/jst/jsp/core/internal/JSPCorePluginResources.properties 19 Mar 2010 20:18:09 -0000 1.33 >+++ src/org/eclipse/jst/jsp/core/internal/JSPCorePluginResources.properties 1 Sep 2010 12:23:07 -0000 >@@ -47,4 +47,7 @@ > TLDValidator_MissingVariable=The variable class '{0}' was not found on the Java Build Path > TLDValidator_MissingListener=The listener class '{0}' was not found on the Java Build Path > Initializing=Processing JSP changes since last activation >-Persisting_JSP_Translations=Persisting JSP Translations >\ No newline at end of file >+Persisting_JSP_Translations=Persisting JSP Translations >+ >+JSPCorePlugin_Initializing_JSP_Tools=Initializing JSP Tools >+JSPIndexManager=JSP Index Manager >\ No newline at end of file >Index: src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java,v >retrieving revision 1.18 >diff -u -r1.18 JSPTranslation.java >--- src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java 15 Apr 2010 02:14:10 -0000 1.18 >+++ src/org/eclipse/jst/jsp/core/internal/java/JSPTranslation.java 1 Sep 2010 12:23:07 -0000 >@@ -16,7 +16,6 @@ > import java.util.Iterator; > import java.util.List; > >-import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.WorkspaceJob; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IProgressMonitor; >@@ -29,7 +28,8 @@ > import org.eclipse.jdt.core.ICompilationUnit; > import org.eclipse.jdt.core.IJavaElement; > import org.eclipse.jdt.core.IJavaProject; >-import org.eclipse.jdt.core.JavaCore; >+import org.eclipse.jdt.core.IPackageFragment; >+import org.eclipse.jdt.core.IPackageFragmentRoot; > import org.eclipse.jdt.core.JavaModelException; > import org.eclipse.jdt.core.WorkingCopyOwner; > import org.eclipse.jface.text.Position; >@@ -436,9 +436,22 @@ > return null; > > final String name = getClassname() + ".java"; >- IFile fakeFile = je.getProject().getFile(name); >- ICompilationUnit fakeUnit = JavaCore.createCompilationUnitFrom(fakeFile); >- ICompilationUnit cu = fakeUnit.getWorkingCopy(getWorkingCopyOwner(), getProgressMonitor()); >+ IPackageFragmentRoot packageFragmentRoot = null; >+ IPackageFragmentRoot[] packageFragmentRoots = je.getPackageFragmentRoots(); >+ for (int i = 0; i < packageFragmentRoots.length; i++) { >+ if (!packageFragmentRoots[i].isArchive() && !packageFragmentRoots[i].isExternal()) { >+ packageFragmentRoot = packageFragmentRoots[i]; >+ break; >+ } >+ } >+ if (packageFragmentRoot == null) { >+ if(DEBUG) { >+ System.out.println("** Abort create working copy: cannot create working copy: JSP is not in a Java project with source package fragment root"); //$NON-NLS-1$ >+ } >+ return null; >+ } >+ final IPackageFragment fragment = packageFragmentRoot.getPackageFragment(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH); >+ ICompilationUnit cu = fragment.getCompilationUnit(name).getWorkingCopy(getWorkingCopyOwner(), getProgressMonitor()); > setContents(cu); > > if(DEBUG) { >Index: src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java,v >retrieving revision 1.17 >diff -u -r1.17 JSPTranslationAdapter.java >--- src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java 28 Jan 2010 19:59:44 -0000 1.17 >+++ src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java 1 Sep 2010 12:23:07 -0000 >@@ -115,7 +115,7 @@ > fDocumentIsDirty = true; > } > >- public void release() { >+ public synchronized void release() { > > if (fJspDocument != null) > fJspDocument.removeDocumentListener(this); >@@ -129,6 +129,7 @@ > System.out.println("JSPTranslationAdapter releasing:" + fJSPTranslation); //$NON-NLS-1$ > > fJSPTranslation.release(); >+ fJSPTranslation = null; > } > } > >Index: src/org/eclipse/jst/jsp/core/internal/java/JSPTranslatorPersister.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslatorPersister.java,v >retrieving revision 1.3 >diff -u -r1.3 JSPTranslatorPersister.java >--- src/org/eclipse/jst/jsp/core/internal/java/JSPTranslatorPersister.java 19 Mar 2010 20:18:09 -0000 1.3 >+++ src/org/eclipse/jst/jsp/core/internal/java/JSPTranslatorPersister.java 1 Sep 2010 12:23:07 -0000 >@@ -17,31 +17,17 @@ > import java.io.InvalidClassException; > import java.io.ObjectInputStream; > import java.io.ObjectOutputStream; >-import java.util.LinkedList; > import java.util.zip.CRC32; > > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IResource; >-import org.eclipse.core.resources.IResourceChangeEvent; >-import org.eclipse.core.resources.IResourceChangeListener; >-import org.eclipse.core.resources.IResourceDelta; >-import org.eclipse.core.resources.IResourceDeltaVisitor; > import org.eclipse.core.resources.ResourcesPlugin; > import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IPath; >-import org.eclipse.core.runtime.IProgressMonitor; >-import org.eclipse.core.runtime.ISafeRunnable; >-import org.eclipse.core.runtime.IStatus; >-import org.eclipse.core.runtime.Platform; >-import org.eclipse.core.runtime.SafeRunner; >-import org.eclipse.core.runtime.Status; >-import org.eclipse.core.runtime.content.IContentType; >-import org.eclipse.core.runtime.jobs.Job; >-import org.eclipse.jst.jsp.core.internal.JSPCoreMessages; > import org.eclipse.jst.jsp.core.internal.JSPCorePlugin; > import org.eclipse.jst.jsp.core.internal.Logger; >+import org.eclipse.jst.jsp.core.internal.java.search.JSPIndexManager; > import org.eclipse.jst.jsp.core.internal.modelhandler.ModelHandlerForJSP; >-import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP; > import org.eclipse.wst.sse.core.StructuredModelManager; > import org.eclipse.wst.sse.core.internal.FileBufferModelManager; > import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; >@@ -49,32 +35,19 @@ > import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; > > /** >- * <p>This {@link IResourceChangeListener} is used to keep the {@link JSPTranslator}s for JSP >- * resources persisted to disk. It can also be used to get persisted translators</p> >- * <p>This class should be registered as an {@link IResourceChangeListener} on the Workspace >- * as well as processing resource change events from a saved state, for example use see below.<p> >- * <p><b>Plugin Activation:</b> >- * <pre> >- * try { >- * ISavedState savedState = ResourcesPlugin.getWorkspace().addSaveParticipant( >- * plugin.getBundle().getSymbolicName(), this.fSaveParticipant); >- * if (savedState != null) { >- * savedState.processResourceChangeEvents(JSPTranslatorPersistor.getDefault()); >- * } >- * } catch(CoreException e) {} >- * ResourcesPlugin.getWorkspace().addResourceChangeListener(JSPTranslatorPersistor.getDefault()); >- * </pre> >- * <b>Plugin Deactivation:</b> >- * <pre> >- * ResourcesPlugin.getWorkspace().removeSaveParticipant(plugin.getBundle().getSymbolicName()); >- * ResourcesPlugin.getWorkspace().removeResourceChangeListener(JSPTranslatorPersistor.getDefault()); >- * </pre></p> >+ * <p>This is a static class used to persist JSP translations and retrieve the persisted >+ * translations.</p> >+ * >+ * <p>It is not actually in charge of finding files to persist, rather it provides API >+ * for some other mechanism that tracks JSP files to call into to persist the translations.</p> > * > * <p>This class can be deactivated through the <code>persistJSPTranslations</code> system property, > * a value of <code>true</code> means the persister is activated (which is the default), value of > * <code>false</code> means the persister is not activated.</p> >+ * >+ * @see JSPIndexManager > */ >-public class JSPTranslatorPersister implements IResourceChangeListener { >+public class JSPTranslatorPersister{ > /** > * <code>true</code> if the persister is activated, <code>false</code> > * otherwise. This is determined by checking the system property >@@ -90,63 +63,10 @@ > /** used to calculate persisted translator file names */ > private static final CRC32 CHECKSUM_CALC = new CRC32(); > >- /** singleton instance of the {@link JSPTranslatorPersister} */ >- private static final JSPTranslatorPersister INSTANCE = new JSPTranslatorPersister(); >- >- /** >- * Used to handle resource change events >- * @see #resourceChanged(IResourceChangeEvent) >- */ >- private IResourceDeltaVisitor fResourceDeltaVisitor; >- >- /** {@link Job} that actually does all the persisting */ >- protected PersisterJob fPersisterJob; >- > /** >- * <p>Private singleton default constructor</p> >+ * <p>Private constructor to prevent creating an instance of this class</p> > */ > private JSPTranslatorPersister() { >- this.fResourceDeltaVisitor = new JSPResourceVisitor(); >- this.fPersisterJob = new PersisterJob(); >- } >- >- /** >- * <p><b>NOTE: </b><i>This can possible return <code>null</code></i></p> >- * >- * @return Singleton instance of the {@link JSPTranslatorPersister} if >- * {@link #ACTIVATED} is <code>true</code>, <code>null</code> otherwise. >- */ >- public static JSPTranslatorPersister getDefault() { >- return ACTIVATED ? INSTANCE : null; >- } >- >- /** >- * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) >- */ >- public void resourceChanged(IResourceChangeEvent event) { >- switch(event.getType()) { >- case IResourceChangeEvent.PRE_CLOSE: >- case IResourceChangeEvent.PRE_DELETE: >- //pre-close or pre-delete stop the persister job so it does not interfere >- this.fPersisterJob.stop(); >- break; >- case IResourceChangeEvent.POST_CHANGE: >- //post change start up the persister job and process the delta >- this.fPersisterJob.start(); >- >- // only analyze the full (starting at root) delta hierarchy >- IResourceDelta delta = event.getDelta(); >- if (delta != null && delta.getFullPath().toString().equals("/")) { //$NON-NLS-1$ >- try { >- //use visitor to visit all children >- delta.accept(this.fResourceDeltaVisitor, false); >- } catch (CoreException e) { >- Logger.logException("Processing resource change event delta failed, " + >- "persisted JSPTranslators may not have been updated.", e); >- } >- } >- break; >- } > } > > /** >@@ -210,6 +130,45 @@ > } > > /** >+ * @param resource JSP resource who's translation should be persisted >+ */ >+ public static void persistTranslation(IResource resource) { >+ if(ACTIVATED) { >+ IPath path = resource.getFullPath(); >+ String filePath = getPersistedTranslatorFilePath(path.toPortableString()); >+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); >+ >+ JSPTranslator translator = getJSPTranslator(file); >+ if(translator != null) { >+ persistTranslator(translator, filePath); >+ } >+ } >+ } >+ >+ /** >+ * @param resource JSP resource who's translation should no longer be persisted >+ */ >+ public static void removePersistedTranslation(IResource resource) { >+ if(ACTIVATED) { >+ File file = getPersistedFile(resource.getFullPath()); >+ deletePersistedTranslator(file); >+ } >+ } >+ >+ /** >+ * @param resource JSP resource that has moved and thus its persisted translation should be updated >+ * @param fromPath Path the JSP resource moved from >+ */ >+ public static void movePersistedTranslation(IResource resource, IPath fromPath) { >+ if(ACTIVATED) { >+ File from = getPersistedFile(fromPath); >+ File to = getPersistedFile(resource.getFullPath()); >+ >+ renamePersistedTranslator(from, to); >+ } >+ } >+ >+ /** > * <p>Given the path to a JSP file determines the path to its persisted {@link JSPTranslator}</p> > * > * @param jspFilePath {@link IPath} to JSP file for which the path to its persisted {@link JSPTranslator} >@@ -218,7 +177,7 @@ > * @return OS file path to the persisted {@link JSPTranslator} associated with the JSP file at > * <code>jspFilePath</code> > */ >- protected static String getPersistedTranslatorFilePath(String jspFilePath) { >+ private static String getPersistedTranslatorFilePath(String jspFilePath) { > CHECKSUM_CALC.reset(); > CHECKSUM_CALC.update(jspFilePath.getBytes()); > String persistedTranslatorFileName = Long.toString(CHECKSUM_CALC.getValue()) + ".translator"; //$NON-NLS-1$ >@@ -240,290 +199,84 @@ > } > > /** >- * @see JSPResourceVisitor#visit(IResourceDelta) >+ * <p>Gets the associated {@link JSPTranslator} for a specific JSP file.</p> >+ * <p><b>NOTE: </b><i>This does not get the persisted translator but rather the >+ * associated translator in memory</i></p> >+ * >+ * @param jspFile {@link IFile} to the JSP file that the associated {@link JSPTranslator} >+ * is needed for >+ * @return {@link JSPTranslator} associated with the given <code>jspFilePath</code>, or >+ * <code>null</code> if none can be found. > */ >- private class JSPResourceVisitor implements IResourceDeltaVisitor { >- /** >- * <p>Default constructor</p> >- */ >- protected JSPResourceVisitor() { >- } >- >- /** >- * <p>For each {@link IResourceDelta} determine if its a JSP resource and if it is >- * add the appropriate action to the {@link PersisterJob} so as not to hold up >- * the {@link IResourceDelta}</p> >- * >- * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta) >- */ >- public boolean visit(IResourceDelta delta) throws CoreException { >- if(isJSPResource(delta.getResource())) { >- switch (delta.getKind()) { >- case IResourceDelta.CHANGED : >- case IResourceDelta.ADDED : { >- /* if a move, then move the persisted translation >- * else create a new persisted translation, if its a change then >- * the old persisted translation will be overwritten */ >- if((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) { >- final File from = getPersistedFile(delta.getMovedFromPath()); >- final File to = getPersistedFile(delta.getFullPath()); >- //add the move action to the persister job >- JSPTranslatorPersister.this.fPersisterJob.addAction(new ISafeRunnable() { >- public void run() throws Exception { >- renamePersistedTranslator(from, to); >- } >- >- public void handleException(Throwable exception) {} >- }); >- } else { >- final String filePath = getPersistedTranslatorFilePath(delta.getFullPath().toPortableString()); >- final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getFullPath()); >- //add the add action to the persister job >- JSPTranslatorPersister.this.fPersisterJob.addAction(new ISafeRunnable() { >- public void run() throws Exception { >- JSPTranslator translator = getJSPTranslator(file); >- if(translator != null) { >- persistTranslator(translator, filePath); >- } >- } >- >- public void handleException(Throwable exception) {} >- }); >- } >- >- break; >- } >- case IResourceDelta.REMOVED : { >- /* only remove if its not a move, >- * if it is a move the added file delta event will move translation */ >- if((delta.getFlags() & IResourceDelta.MOVED_TO) == 0) { >- final File file = getPersistedFile(delta.getFullPath()); >- //add the delete action to the persister job >- JSPTranslatorPersister.this.fPersisterJob.addAction(new ISafeRunnable() { >- public void run() throws Exception { >- deletePersistedTranslator(file); >- } >- >- public void handleException(Throwable exception) {} >- }); >- } >- break; >- } >- } >- } >- >- //visit children deltas >- return true; >- } >- >- /** >- * <p>Determines if an {@link IResource} is a JSP resource</p> >- * >- * @param resource determine if this {@link IResource} is a JSP resource >- * @return <code>true</code> if <code>resource</code> is a JSP resource, >- * <code>false</code> otherwise. >- */ >- private boolean isJSPResource(IResource resource) { >- boolean isJSP = false; >- >- //general rule for getting files in the workspace >- if(resource.getFullPath().segmentCount() >= 2) { >- IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(resource.getFullPath()); >- if(file.getType() == IResource.FILE) { >- //get JSP content type each time because there is a possibility it could change >- IContentType contentTypeJSP = Platform.getContentTypeManager().getContentType( >- ContentTypeIdForJSP.ContentTypeID_JSP); >- >- isJSP = contentTypeJSP.isAssociatedWith(file.getName()); >- } >- } >- >- return isJSP; >- } >- >- /** >- * <p>Gets the associated {@link JSPTranslator} for a specific JSP file.</p> >- * <p><b>NOTE: </b><i>This does not get the persisted translator but rather the >- * associated translator in memory</i></p> >- * >- * @param jspFile {@link IFile} to the JSP file that the associated {@link JSPTranslator} >- * is needed for >- * @return {@link JSPTranslator} associated with the given <code>jspFilePath</code>, or >- * <code>null</code> if none can be found. >- */ >- protected JSPTranslator getJSPTranslator(IFile jspFile) { >- IStructuredModel model = null; >- JSPTranslator translator = null; >- try { >- model = StructuredModelManager.getModelManager().getModelForRead(jspFile); >- if(model instanceof IDOMModel) { >- IDOMDocument doc = ((IDOMModel)model).getDocument(); >- ModelHandlerForJSP.ensureTranslationAdapterFactory(model); >- JSPTranslationAdapter adapter = (JSPTranslationAdapter)doc.getAdapterFor(IJSPTranslation.class); >- >- //don't want to persist a translator that has not already been requested >- if(adapter != null && adapter.hasTranslation()) { >- translator = adapter.getJSPTranslation().getTranslator(); >- } >- } >- } catch (IOException e) { >- Logger.logException("Could not get translator for " + jspFile.getName() + //$NON-NLS-1$ >- " because could not read model for same.", e); //$NON-NLS-1$ >- } catch (CoreException e) { >- Logger.logException("Could not get translator for " + jspFile.getName() + //$NON-NLS-1$ >- " because could not read model for same.", e); //$NON-NLS-1$ >- } finally { >- if(model != null) { >- model.releaseFromRead(); >+ private static JSPTranslator getJSPTranslator(IFile jspFile) { >+ IStructuredModel model = null; >+ JSPTranslator translator = null; >+ try { >+ model = StructuredModelManager.getModelManager().getModelForRead(jspFile); >+ if(model instanceof IDOMModel) { >+ IDOMDocument doc = ((IDOMModel)model).getDocument(); >+ ModelHandlerForJSP.ensureTranslationAdapterFactory(model); >+ JSPTranslationAdapter adapter = (JSPTranslationAdapter)doc.getAdapterFor(IJSPTranslation.class); >+ >+ //don't want to persist a translator that has not already been requested >+ if(adapter != null && adapter.hasTranslation()) { >+ translator = adapter.getJSPTranslation().getTranslator(); > } > } >- >- return translator; >- } >- >- /** >- * <p>Persists a {@link JSPTranslator} to disk for a specific JSP file</p> >- * >- * @param translator {@link JSPTranslator} to persist to disk >- * @param jspFilePath {@link IPath} to the JSP file the given <code>translator</code> is for >- */ >- protected void persistTranslator(JSPTranslator translator, String filePath) { >- try { >- FileOutputStream fos = new FileOutputStream(filePath); >- ObjectOutputStream out = new ObjectOutputStream(fos); >- out.writeObject(translator); >- out.close(); >- } catch (IOException e) { >- Logger.logException("Was unable to externalize JSPTranslator " + translator + //$NON-NLS-1$ >- " to " + filePath, e); //$NON-NLS-1$ >+ } catch (IOException e) { >+ Logger.logException("Could not get translator for " + jspFile.getName() + //$NON-NLS-1$ >+ " because could not read model for same.", e); //$NON-NLS-1$ >+ } catch (CoreException e) { >+ Logger.logException("Could not get translator for " + jspFile.getName() + //$NON-NLS-1$ >+ " because could not read model for same.", e); //$NON-NLS-1$ >+ } finally { >+ if(model != null) { >+ model.releaseFromRead(); > } > } > >- /** >- * <p>Deletes a persisted translation for a JSP file that has been deleted</p> >- * >- * @param jspFilePath {@link IPath} to the JSP file that has been deleted >- */ >- protected void deletePersistedTranslator(File file) { >- file.delete(); >- } >- >- /** >- * <p>Renames a persisted translation for a JSP file that has moved</p> >- * >- * @param jspPrevFilePath {@link IPath} to the previous location of JSP file</p> >- * @param jspNewFilePath {@link IPath} to new location of JSP file</p> >- */ >- protected void renamePersistedTranslator(File from, File to) { >- //do the move >- from.renameTo(to); >- } >- >- private File getPersistedFile(IPath path) { >- return new File(getPersistedTranslatorFilePath(path.toPortableString())); >- } >+ return translator; > } > > /** >- * <p>{@link Job} responsible for reacting to {@link IResourceDelta} visited >- * by {@link JSPResourceVisitor}. This way the actions that need to be taken >- * in reaction to the delta to not hold up the {@link IResourceChangeListener} >- * or the {@link IResourceDelta}.</p> >- * >- */ >- private class PersisterJob extends Job { >- /** Length to delay when scheduling job */ >- private static final int DELAY = 500; >- >- /** >- * <code>{@link LinkedList}<{@link ISafeRunnable}></code> >- * <p>The persister actions that have been queued up by the {@link JSPResourceVisitor}</p> >- */ >- private LinkedList fActions; >- >- /** Whether this job has been stopped or not */ >- private boolean fIsStopped; >- >- /** >- * <p>Sets job up as a system job</p> >- */ >- protected PersisterJob() { >- super(JSPCoreMessages.Persisting_JSP_Translations); >- this.setUser(false); >- this.setSystem(true); >- this.setPriority(Job.LONG); >- >- this.fActions = new LinkedList(); >- this.fIsStopped = false; >- } >- >- /** >- * <p>Starts this job. This has no effect if the job is already started.</p> >- * <p>This should be used in place of {@link Job#schedule()} to reset state >- * caused by calling {@link #stop()}</p> >- * >- * @see #stop() >- */ >- protected synchronized void start() { >- this.fIsStopped = false; >- >- //get the job running again depending on its current state >- if(this.getState() == Job.SLEEPING) { >- this.wakeUp(DELAY); >- } else { >- this.schedule(DELAY); >- } >- } >- >- /** >- * <p>Stops this job, even if it is running</p> >- * <p>This should be used in place of {@link Job#sleep()} because {@link Job#sleep()} >- * will not stop a job that is already running but calling this will stop this job >- * even if it is running. {@link #start()} must be used to start this job again</p> >- * >- * @see #start() >- */ >- protected synchronized void stop() { >- //sleep the job if it is waiting to run >- this.sleep(); >- >- //if job is already running will force it to stop >- this.fIsStopped = true; >- } >- >- /** >- * @param action {@link ISafeRunnable} containing a persister action to take >- * based on an {@link IResourceDelta} processed by {@link JSPResourceVisitor} >- */ >- protected void addAction(ISafeRunnable action) { >- //add the action >- synchronized (this.fActions) { >- this.fActions.addLast(action); >- } >- >- //if job has not been manually stopped, then start it >- if(!this.fIsStopped) { >- this.start(); >- } >+ * <p>Persists a {@link JSPTranslator} to disk for a specific JSP file</p> >+ * >+ * @param translator {@link JSPTranslator} to persist to disk >+ * @param jspFilePath {@link IPath} to the JSP file the given <code>translator</code> is for >+ */ >+ private static void persistTranslator(JSPTranslator translator, String filePath) { >+ try { >+ FileOutputStream fos = new FileOutputStream(filePath); >+ ObjectOutputStream out = new ObjectOutputStream(fos); >+ out.writeObject(translator); >+ out.close(); >+ } catch (IOException e) { >+ Logger.logException("Was unable to externalize JSPTranslator " + translator + //$NON-NLS-1$ >+ " to " + filePath, e); //$NON-NLS-1$ > } >+ } >+ >+ /** >+ * <p>Deletes a persisted translation for a JSP file that has been deleted</p> >+ * >+ * @param jspFilePath {@link IPath} to the JSP file that has been deleted >+ */ >+ private static void deletePersistedTranslator(File file) { >+ file.delete(); >+ } >+ >+ /** >+ * <p>Renames a persisted translation for a JSP file that has moved</p> >+ * >+ * @param jspPrevFilePath {@link IPath} to the previous location of JSP file</p> >+ * @param jspNewFilePath {@link IPath} to new location of JSP file</p> >+ */ >+ private static void renamePersistedTranslator(File from, File to) { >+ //do the move >+ from.renameTo(to); >+ } > >- /** >- * <p>Process the actions until there are none left</p> >- * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) >- */ >- protected IStatus run(IProgressMonitor monitor) { >- /* run so long as job has not been stopped, >- *monitor canceled, and have actions to process */ >- while(!this.fIsStopped && !monitor.isCanceled() && !this.fActions.isEmpty()) { >- ISafeRunnable action; >- synchronized (this.fActions) { >- action = (ISafeRunnable)this.fActions.removeFirst(); >- } >- >- SafeRunner.run(action); >- } >- >- return Status.OK_STATUS; >- } >+ private static File getPersistedFile(IPath path) { >+ return new File(getPersistedTranslatorFilePath(path.toPortableString())); > } > } >\ No newline at end of file >Index: src/org/eclipse/jst/jsp/core/internal/java/search/IndexWorkspaceJob.java >=================================================================== >RCS file: src/org/eclipse/jst/jsp/core/internal/java/search/IndexWorkspaceJob.java >diff -N src/org/eclipse/jst/jsp/core/internal/java/search/IndexWorkspaceJob.java >--- src/org/eclipse/jst/jsp/core/internal/java/search/IndexWorkspaceJob.java 11 Dec 2008 01:36:27 -0000 1.10 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,163 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2004, 2005 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.jst.jsp.core.internal.java.search; >- >-import java.util.ArrayList; >-import java.util.List; >- >-import org.eclipse.core.resources.IFile; >-import org.eclipse.core.resources.IResource; >-import org.eclipse.core.resources.IResourceProxy; >-import org.eclipse.core.resources.IResourceProxyVisitor; >-import org.eclipse.core.resources.ResourcesPlugin; >-import org.eclipse.core.runtime.CoreException; >-import org.eclipse.core.runtime.IProgressMonitor; >-import org.eclipse.core.runtime.IStatus; >-import org.eclipse.core.runtime.Platform; >-import org.eclipse.core.runtime.Status; >-import org.eclipse.core.runtime.content.IContentType; >-import org.eclipse.core.runtime.jobs.Job; >-import org.eclipse.jst.jsp.core.internal.JSPCoreMessages; >-import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP; >- >-/** >- * Re-indexes the entire workspace. >- * Ensures the JSP Index is in a stable state before performing a search. >- * (like after a crash or if previous indexing was canceled) >- * >- * @author pavery >- */ >-public class IndexWorkspaceJob extends Job { >- >- // for debugging >- static final boolean DEBUG; >- static { >- String value= Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/jspindexmanager"); //$NON-NLS-1$ >- DEBUG= value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ >- } >- >- /** >- * Visitor that retrieves jsp project paths for all jsp files in the workspace, >- * and adds the files to be indexed as they are encountered >- */ >- private class JSPFileVisitor implements IResourceProxyVisitor { >- private List files = new ArrayList(); >- >- // monitor from the Job >- IProgressMonitor fInnerMonitor = null; >- public JSPFileVisitor(IProgressMonitor monitor) { >- this.fInnerMonitor = monitor; >- } >- >- public boolean visit(IResourceProxy proxy) throws CoreException { >- >- // check job canceled >- if (this.fInnerMonitor != null && this.fInnerMonitor.isCanceled()) { >- setCanceledState(); >- return false; >- } >- >- // check search support canceled >- if(JSPSearchSupport.getInstance().isCanceled()) { >- setCanceledState(); >- return false; >- } >- >- if (proxy.getType() == IResource.FILE) { >- >- // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3553 >- // check this before description >- // check name before actually getting the file (less work) >- if(getJspContentType().isAssociatedWith(proxy.getName())) { >- IFile file = (IFile) proxy.requestResource(); >- if(file.exists()) { >- >- if(DEBUG) >- System.out.println("(+) IndexWorkspaceJob adding file: " + file.getName()); //$NON-NLS-1$ >- // this call will check the ContentTypeDescription, so don't need to do it here. >- //JSPSearchSupport.getInstance().addJspFile(file); >- this.files.add(file); >- this.fInnerMonitor.subTask(proxy.getName()); >- >- // don't search deeper for files >- return false; >- } >- } >- } >- return true; >- } >- >- public final IFile[] getFiles() { >- return (IFile[])this.files.toArray(new IFile[this.files.size()]); >- } >- } >- >- private IContentType fContentTypeJSP = null; >- >- public IndexWorkspaceJob() { >- // pa_TODO may want to say something like "Rebuilding JSP Index" to be more >- // descriptive instead of "Updating JSP Index" since they are 2 different things >- super(JSPCoreMessages.JSPIndexManager_0); >- setPriority(Job.LONG); >- setSystem(true); >- } >- >- IContentType getJspContentType() { >- if(this.fContentTypeJSP == null) >- this.fContentTypeJSP = Platform.getContentTypeManager().getContentType(ContentTypeIdForJSP.ContentTypeID_JSP); >- return this.fContentTypeJSP; >- } >- >- /** >- * @see org eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor) >- * for similar method >- */ >- protected IStatus run(IProgressMonitor monitor) { >- >- IStatus status = Status.OK_STATUS; >- Thread.currentThread().setPriority(Thread.MIN_PRIORITY); >- >- if(monitor.isCanceled()) { >- setCanceledState(); >- return Status.CANCEL_STATUS; >- } >- >- if(DEBUG) >- System.out.println(" ^ IndexWorkspaceJob started: "); //$NON-NLS-1$ >- >- long start = System.currentTimeMillis(); >- >- try { >- JSPFileVisitor visitor = new JSPFileVisitor(monitor); >- // collect all jsp files >- ResourcesPlugin.getWorkspace().getRoot().accept(visitor, IResource.DEPTH_INFINITE); >- // request indexing >- // this is pretty much like faking an entire workspace resource delta >- JSPIndexManager.getInstance().indexFiles(visitor.getFiles()); >- } >- catch (CoreException e) { >- if(DEBUG) >- e.printStackTrace(); >- } >- finally { >- monitor.done(); >- } >- long finish = System.currentTimeMillis(); >- if(DEBUG) >- System.out.println(" ^ IndexWorkspaceJob finished\n total time running: " + (finish - start)); //$NON-NLS-1$ >- >- return status; >- } >- >- void setCanceledState() { >- JSPIndexManager.getInstance().setIndexState(JSPIndexManager.S_CANCELED); >- } >-} >Index: src/org/eclipse/jst/jsp/core/internal/java/search/JSPIndexManager.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/search/JSPIndexManager.java,v >retrieving revision 1.27 >diff -u -r1.27 JSPIndexManager.java >--- src/org/eclipse/jst/jsp/core/internal/java/search/JSPIndexManager.java 5 Apr 2010 19:13:27 -0000 1.27 >+++ src/org/eclipse/jst/jsp/core/internal/java/search/JSPIndexManager.java 1 Sep 2010 12:23:07 -0000 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2004, 2010 IBM Corporation and others. >+ * Copyright (c) 2010 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 >@@ -7,725 +7,146 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >+ * > *******************************************************************************/ > package org.eclipse.jst.jsp.core.internal.java.search; > > import java.io.File; >-import java.util.ArrayList; >-import java.util.HashMap; >-import java.util.List; > > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; >-import org.eclipse.core.resources.IResourceChangeEvent; >-import org.eclipse.core.resources.IResourceChangeListener; >-import org.eclipse.core.resources.IResourceDelta; >-import org.eclipse.core.resources.IResourceDeltaVisitor; >-import org.eclipse.core.resources.ResourcesPlugin; >-import org.eclipse.core.runtime.CoreException; > import org.eclipse.core.runtime.IPath; >-import org.eclipse.core.runtime.IProgressMonitor; >-import org.eclipse.core.runtime.IStatus; > import org.eclipse.core.runtime.Platform; >-import org.eclipse.core.runtime.Plugin; >-import org.eclipse.core.runtime.Status; > import org.eclipse.core.runtime.content.IContentType; >-import org.eclipse.core.runtime.jobs.IJobChangeEvent; >-import org.eclipse.core.runtime.jobs.Job; >-import org.eclipse.core.runtime.jobs.JobChangeAdapter; > import org.eclipse.jdt.core.IJavaProject; > import org.eclipse.jdt.core.JavaCore; >-import org.eclipse.jdt.internal.core.JavaModelManager; >-import org.eclipse.jdt.internal.core.index.Index; >-import org.eclipse.jdt.internal.core.search.indexing.IndexManager; > import org.eclipse.jst.jsp.core.internal.JSPCoreMessages; > import org.eclipse.jst.jsp.core.internal.JSPCorePlugin; > import org.eclipse.jst.jsp.core.internal.Logger; >+import org.eclipse.jst.jsp.core.internal.java.JSPTranslatorPersister; > import org.eclipse.jst.jsp.core.internal.provisional.contenttype.ContentTypeIdForJSP; >-import org.eclipse.osgi.util.NLS; >-import org.osgi.framework.Bundle; >+import org.eclipse.wst.sse.core.indexing.AbstractIndexManager; > > /** >- * Responsible for keeping the JSP index up to date. >+ * <p>Index manger used to update the JDT index with the Java translations >+ * of JSPs.</p> > * >- * @author pavery >+ * <p>Also keeps JSP persistence up to date</p> >+ * >+ * <p>Any action that needs the JDT index to have all of the latest JSP changes processed >+ * should wait for this manger to report that it is consistent, >+ * {@link #waitForConsistant(org.eclipse.core.runtime.IProgressMonitor)}. Such actions >+ * include but are not limited to searching and refactoring JSPs.</p> > */ >-public class JSPIndexManager { >- >- // for debugging >- // TODO move this to Logger, as we have in SSE >- static final boolean DEBUG; >- static { >- String value = Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/jspindexmanager"); //$NON-NLS-1$ >- DEBUG = value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ >- } >- >- private static final String PKEY_INDEX_STATE = "jspIndexState"; //$NON-NLS-1$ >- >- private IndexWorkspaceJob indexingJob = new IndexWorkspaceJob(); >- >- >- >- // TODO: consider enumeration for these int constants >- // set to S_UPDATING once a resource change comes in >- // set to S_STABLE if: >- // - we know we aren't interested in the resource change >- // - or the ProcessFilesJob completes >- // set to S_CANCELED if an indexing job is canceled >- // set to S_REBUILDING if re-indexing the entire workspace >- >- // the int '0' is reserved for the default value if a preference is not >- // there >- /** index is reliable to use */ >- public static final int S_STABLE = 1; >- /** index is being updated (from a resource delta) */ >- public static final int S_UPDATING = 2; >- /** entire index is being rebuilt */ >- public static final int S_REBUILDING = 3; >- /** >- * indexing job was canceled in the middle of it, index needs to be >- * rebuilt >- */ >- public static final int S_CANCELED = 4; >- >- /** symbolic name for OSGI framework */ >- private final String OSGI_FRAMEWORK_ID = "org.eclipse.osgi"; //$NON-NLS-1$ >- >- /** >- * Collects JSP files from a resource delta. >- */ >- private class JSPResourceVisitor implements IResourceDeltaVisitor { >- // using hash map ensures only one of each file >- // must be reset before every use >- private HashMap jspFiles = null; >- >- public JSPResourceVisitor() { >- this.jspFiles = new HashMap(); >- } >- >- public boolean visit(IResourceDelta delta) throws CoreException { >- >- // in case JSP search was canceled (eg. when closing the editor) >- if (JSPSearchSupport.getInstance().isCanceled() || frameworkIsShuttingDown()) { >- setCanceledState(); >- return false; >- } >- >- try { >- if (!isHiddenResource(delta.getFullPath())) { >- >- int kind = delta.getKind(); >- boolean added = (kind & IResourceDelta.ADDED) == IResourceDelta.ADDED; >- boolean isInterestingChange = false; >- if ((kind & IResourceDelta.CHANGED) == IResourceDelta.CHANGED) { >- int flags = delta.getFlags(); >- // ignore things like marker changes >- isInterestingChange = (flags & IResourceDelta.CONTENT) == IResourceDelta.CONTENT || (flags & IResourceDelta.REPLACED) == IResourceDelta.REPLACED; >- } >- boolean removed = (kind & IResourceDelta.REMOVED) == IResourceDelta.REMOVED; >- if (added || isInterestingChange) { >- >- visitAdded(delta); >- } >- else if (removed) { >- visitRemoved(delta); >- } >- } >- } >- catch (Exception e) { >- // need to set state here somehow, and reindex >- // otherwise index will be unreliable >- if (DEBUG) >- Logger.logException("Delta analysis may not be complete", e); //$NON-NLS-1$ >- } >- // if the delta has children, continue to add/remove files >- return true; >- } >- >- private void visitRemoved(IResourceDelta delta) { >- // handle cleanup >- if (delta.getResource() != null) { >- IResource r = delta.getResource(); >- if (r.getType() == IResource.FOLDER && r.exists()) { >- deleteIndex((IFile) r); >- } >- } >- } >- >- private void visitAdded(IResourceDelta delta) { >- // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3553 >- // quick check if it's even JSP related to improve >- // performance >- // checking name from the delta before getting >- // resource because it's lighter >- String filename = delta.getFullPath().lastSegment(); >- if (filename != null && getJspContentType().isAssociatedWith(filename)) { >- IResource r = delta.getResource(); >- if (r != null && r.exists() && r.getType() == IResource.FILE) { >- this.jspFiles.put(r.getFullPath(), r); >- } >- } >- } >- >- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=93463 >- private boolean isHiddenResource(IPath p) { >- String[] segments = p.segments(); >- for (int i = 0; i < segments.length; i++) { >- if (segments[i].startsWith(".")) //$NON-NLS-1$ >- return true; >- } >- return false; >- } >- >- private void deleteIndex(IFile folder) { >- // cleanup index >- IndexManager im = JavaModelManager.getIndexManager(); >- IPath folderPath = folder.getFullPath(); >- IPath indexLocation = JSPSearchSupport.getInstance().computeIndexLocation(folderPath); >- im.removeIndex(indexLocation); >- // im.indexLocations.removeKey(folderPath); >- // im.indexLocations.removeValue(indexLocation); >- File f = indexLocation.toFile(); >- f.delete(); >- } >- >- public IFile[] getFiles() { >- return (IFile[]) this.jspFiles.values().toArray(new IFile[this.jspFiles.size()]); >- } >- >- public void reset() { >- this.jspFiles.clear(); >- } >- } >- >- // end class JSPResourceVisitor >- >+public class JSPIndexManager extends AbstractIndexManager { >+ /** the singleton instance of the {@link JSPIndexManager} */ >+ private static JSPIndexManager INSTANCE; >+ >+ /** the JSP {@link IContentType} */ >+ private static final IContentType JSP_CONTENT_TYPE = >+ Platform.getContentTypeManager().getContentType(ContentTypeIdForJSP.ContentTypeID_JSP); >+ >+ /** the location to store state */ >+ private IPath fWorkingLocation; >+ > /** >- * schedules JSP files for indexing by Java core >+ * <p>Private singleton constructor</p> > */ >- private class ProcessFilesJob extends Job { >- List fileList = null; >- // keep track of how many files we've indexed >- int lastFileCursor = 0; >- >- ProcessFilesJob(String taskName) { >- super(taskName); >- fileList = new ArrayList(); >- } >- >- synchronized void process(IFile[] files) { >- for (int i = 0; i < files.length; i++) { >- fileList.add(files[i]); >- } >- if (DEBUG) { >- System.out.println("JSPIndexManager queuing " + files.length + " files"); //$NON-NLS-2$ //$NON-NLS-1$ >- } >- } >- >- synchronized IFile[] getFiles() { >- return (IFile[]) fileList.toArray(new IFile[fileList.size()]); >- } >- >- synchronized void clearFiles() { >- fileList.clear(); >- lastFileCursor = 0; >- //System.out.println("cleared files"); >- } >- >- protected IStatus run(IProgressMonitor monitor) { >- // System.out.println("indexer monitor" + monitor); >- if (isCanceled(monitor) || frameworkIsShuttingDown()) { >- setCanceledState(); >- return Status.CANCEL_STATUS; >- } >- >- Thread.currentThread().setPriority(Thread.MIN_PRIORITY); >- long start = System.currentTimeMillis(); >- >- try { >- IFile[] filesToBeProcessed = getFiles(); >- >- if (DEBUG) { >- System.out.println("JSPIndexManager indexing " + filesToBeProcessed.length + " files"); //$NON-NLS-2$ //$NON-NLS-1$ >- } >- // API indicates that monitor is never null >- monitor.beginTask("", filesToBeProcessed.length); //$NON-NLS-1$ >- JSPSearchSupport ss = JSPSearchSupport.getInstance(); >- String processingNFiles = ""; //$NON-NLS-1$ >- >- >- for (;lastFileCursor < filesToBeProcessed.length; lastFileCursor++) { >- >- if (isCanceled(monitor) || frameworkIsShuttingDown()) { >- setCanceledState(); >- return Status.CANCEL_STATUS; >- } >- IFile file = filesToBeProcessed[lastFileCursor]; >- try { >- IProject project = file.getProject(); >- if (project != null) { >- IJavaProject jproject = JavaCore.create(project); >- if (jproject.exists()) { >- ss.addJspFile(file); >- if (DEBUG) { >- System.out.println("JSPIndexManager Job added file: " + file.getName()); //$NON-NLS-1$ >- } >- } >- // JSP Indexer processing n files >- processingNFiles = NLS.bind(JSPCoreMessages.JSPIndexManager_2, new String[]{Integer.toString((filesToBeProcessed.length - lastFileCursor))}); >- monitor.subTask(processingNFiles + " - " + file.getName()); //$NON-NLS-1$ >- monitor.worked(1); >- } >- } >- catch (Exception e) { >- // RATLC00284776 >- // ISSUE: we probably shouldn't be catching EVERY >- // exception, but >- // the framework only allows to return IStatus in >- // order to communicate >- // that something went wrong, which means the loop >- // won't complete, and we would hit the same problem >- // the next time. >- // >- // a possible solution is to keep track of the >- // exceptions logged >- // and only log a certain amt of the same one, >- // otherwise skip it. >- if (!frameworkIsShuttingDown()) { >- String filename = file != null ? file.getFullPath().toString() : ""; //$NON-NLS-1$ >- Logger.logException("JSPIndexer problem indexing:" + filename, e); //$NON-NLS-1$ >- } >- } >- } // end for >- } >- finally { >- // just in case something didn't follow API (monitor is null) >- if (monitor != null) >- monitor.done(); >- } >- >- // successfully finished, clear files list >- clearFiles(); >- >- long finish = System.currentTimeMillis(); >- long diff = finish - start; >- if (DEBUG) { >- fTotalTime += diff; >- System.out.println("============================================================================"); //$NON-NLS-1$ >- System.out.println("this time: " + diff + " cumulative time for resource changed: " + fTotalTime); //$NON-NLS-1$ //$NON-NLS-2$ >- System.out.println("============================================================================"); //$NON-NLS-1$ >- } >- return Status.OK_STATUS; >- } >- >- private boolean isCanceled(IProgressMonitor runMonitor) { >- >- boolean canceled = false; >- // check specific monitor passed into run method (the progress >- // group in this case) >- // check main search support canceled >- if (runMonitor != null && runMonitor.isCanceled()) >- canceled = true; >- else if (JSPSearchSupport.getInstance().isCanceled()) { >- canceled = true; >- if (runMonitor != null) { >- runMonitor.setCanceled(true); >- } >- } >- return canceled; >- } >- >- } >- >- // end class ProcessFilesJob >- >- private static JSPIndexManager fSingleton = null; >- private boolean initialized; >- private boolean initializing = true; >- >- private IndexJobCoordinator indexJobCoordinator; >- private IResourceChangeListener jspResourceChangeListener; >- >- private JSPResourceVisitor fVisitor = null; >- private IContentType fContentTypeJSP = null; >- >- static long fTotalTime = 0; >- >- // Job for processing resource delta >- private ProcessFilesJob processFilesJob = null; >- > private JSPIndexManager() { >- processFilesJob = new ProcessFilesJob(JSPCoreMessages.JSPIndexManager_0); >- // only show in verbose mode >- processFilesJob.setSystem(true); >- processFilesJob.setPriority(Job.LONG); >- processFilesJob.addJobChangeListener(new JobChangeAdapter() { >- public void done(IJobChangeEvent event) { >- super.done(event); >- setStableState(); >- } >- }); >- } >- >- public synchronized static JSPIndexManager getInstance() { >- >- if (fSingleton == null) >- fSingleton = new JSPIndexManager(); >- return fSingleton; >- } >- >- public void initialize() { >- >- JSPIndexManager singleInstance = getInstance(); >- >- >- if (!singleInstance.initialized) { >- singleInstance.initialized = true; >- singleInstance.initializing = true; >- >- singleInstance.indexJobCoordinator = new IndexJobCoordinator(); >- singleInstance.jspResourceChangeListener = new JSPResourceChangeListener(); >- >- // added as JobChange listener so JSPIndexManager can be smarter >- // about when it runs >- Platform.getJobManager().addJobChangeListener(singleInstance.indexJobCoordinator); >- >- // add JSPIndexManager to keep JSP Index up to date >- // listening for IResourceChangeEvent.PRE_DELETE and >- // IResourceChangeEvent.POST_CHANGE >- ResourcesPlugin.getWorkspace().addResourceChangeListener(jspResourceChangeListener, IResourceChangeEvent.POST_CHANGE); >- >- // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=5091 >- // makes sure IndexManager is aware of our indexes >- saveIndexes(); >- singleInstance.initializing = false; >- } >- >+ super(JSPCoreMessages.JSPIndexManager); > } > >- synchronized void setIndexState(int state) { >- if (DEBUG) { >- System.out.println("JSPIndexManager setting index state to: " + state2String(state)); //$NON-NLS-1$ >- } >- Plugin jspModelPlugin = JSPCorePlugin.getDefault(); >- jspModelPlugin.getPluginPreferences().setValue(PKEY_INDEX_STATE, state); >- jspModelPlugin.savePluginPreferences(); >- >- } >- >- private String state2String(int state) { >- String s = "UNKNOWN"; //$NON-NLS-1$ >- switch (state) { >- case (S_STABLE) : >- s = "S_STABLE"; //$NON-NLS-1$ >- break; >- case (S_UPDATING) : >- s = "S_UPDATING"; //$NON-NLS-1$ >- break; >- case (S_CANCELED) : >- s = "S_CANCELED"; //$NON-NLS-1$ >- break; >- case (S_REBUILDING) : >- s = "S_REBUILDING"; //$NON-NLS-1$ >- break; >- } >- return s; >- } >- >- int getIndexState() { >- return JSPCorePlugin.getDefault().getPluginPreferences().getInt(PKEY_INDEX_STATE); >- } >- >- void setUpdatingState() { >- //if (getIndexState() != S_CANCELED) >- setIndexState(S_UPDATING); >- } >- >- void setCanceledState() { >- setIndexState(JSPIndexManager.S_CANCELED); >- } >- >- void setStableState() { >- //if (getIndexState() != S_CANCELED) >- setIndexState(S_STABLE); >- } >- >- void setRebuildingState() { >- setIndexState(S_REBUILDING); >- } >- >- synchronized void rebuildIndexIfNeeded() { >- if (getIndexState() != S_STABLE) { >- rebuildIndex(); >- } >- } >- >- void rebuildIndex() { >- >- if (DEBUG) >- System.out.println("*** JSP Index unstable, requesting re-indexing"); //$NON-NLS-1$ >- >- getIndexingJob().addJobChangeListener(new JobChangeAdapter() { >- public void aboutToRun(IJobChangeEvent event) { >- super.aboutToRun(event); >- setRebuildingState(); >- } >- >- public void done(IJobChangeEvent event) { >- super.done(event); >- setStableState(); >- getIndexingJob().removeJobChangeListener(this); >- } >- }); >- // we're about to reindex everything anyway >- getProcessFilesJob().clearFiles(); >- getIndexingJob().schedule(); >- >- } >- > /** >- * Creates and schedules a Job to process collected files. All JSP >- * indexing should be done through this method or processFiles(IFile file) >- * >- * @param files >+ * @return the singleton instance of the {@link JSPIndexManager} > */ >- final void indexFiles(IFile[] files) { >- // don't use this rule >- // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=4931 >- // processFiles.setRule(new IndexFileRule()); >- processFilesJob.process(files); >+ public static JSPIndexManager getDefault() { >+ return INSTANCE != null ? INSTANCE : (INSTANCE = new JSPIndexManager()); > } > >- > /** >- * Package protected for access by inner Job class in resourceChanged(...) >- * >- * @return >+ * @see indexer.internal.indexing.AbstractIndexManager#isResourceToIndex(int, java.lang.String) > */ >- JSPResourceVisitor getVisitor() { >- >- if (this.fVisitor == null) { >- this.fVisitor = new JSPResourceVisitor(); >- } >- return this.fVisitor; >- } >- >- // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=5091 >- // makes sure IndexManager is aware of our indexes >- void saveIndexes() { >- IndexManager indexManager = JavaModelManager.getIndexManager(); >- IPath jspModelWorkingLocation = JSPSearchSupport.getInstance().getModelJspPluginWorkingLocation(); >- >- File folder = new File(jspModelWorkingLocation.toOSString()); >- String[] files = folder.list(); >- String locay = ""; //$NON-NLS-1$ >- Index index = null; >- try { >- for (int i = 0; i < files.length; i++) { >- if (files[i].toLowerCase().endsWith(".index")) { //$NON-NLS-1$ >- locay = jspModelWorkingLocation.toString() + "/" + files[i]; //$NON-NLS-1$ >- // reuse index file >- index = new Index(locay, "Index for " + locay, true); //$NON-NLS-1$ >- indexManager.saveIndex(index); >- } >- } >- } >- catch (Exception e) { >- // we should be shutting down, want to shut down quietly >- if (DEBUG) >- e.printStackTrace(); >- } >- } >- >- IContentType getJspContentType() { >- if (this.fContentTypeJSP == null) >- this.fContentTypeJSP = Platform.getContentTypeManager().getContentType(ContentTypeIdForJSP.ContentTypeID_JSP); >- return this.fContentTypeJSP; >+ protected boolean isResourceToIndex(int type, String name) { >+ return type == IResource.FILE && JSP_CONTENT_TYPE.isAssociatedWith(name); > } > > /** >- * A check to see if the OSGI framework is shutting down. >- * >- * @return true if the System Bundle is stopped (ie. the framework is >- * shutting down) >+ * @see indexer.internal.indexing.AbstractIndexManager#getWorkingLocation() > */ >- boolean frameworkIsShuttingDown() { >- // in the Framework class there's a note: >- // set the state of the System Bundle to STOPPING. >- // this must be done first according to section 4.19.2 from the OSGi >- // R3 spec. >- boolean shuttingDown = Platform.getBundle(OSGI_FRAMEWORK_ID).getState() == Bundle.STOPPING; >- if (DEBUG && shuttingDown) { >- System.out.println("JSPIndexManager: system is shutting down!"); //$NON-NLS-1$ >- } >- return shuttingDown; >- } >- >+ protected IPath getWorkingLocation() { >+ if(this.fWorkingLocation == null) { >+ //create path to working area >+ IPath workignLocation = >+ JSPCorePlugin.getDefault().getStateLocation().append("jspsearch"); //$NON-NLS-1$ > >- public void shutdown() { >- >- // stop listening >- ResourcesPlugin.getWorkspace().removeResourceChangeListener(jspResourceChangeListener); >- >- >- // stop any searching >- JSPSearchSupport.getInstance().setCanceled(true); >- >- // stop listening to jobs >- Platform.getJobManager().removeJobChangeListener(indexJobCoordinator); >- >- >- int maxwait = 5000; >- if (processFilesJob != null) { >- processFilesJob.cancel(); >- } >- // attempt to make sure this indexing job is litterally >- // done before continuing, since we are shutting down >- waitTillNotRunning(maxwait, processFilesJob); >- >- if (indexingJob != null) { >- indexingJob.cancel(); >- } >- waitTillNotRunning(maxwait, processFilesJob); >- } >- >- private void waitTillNotRunning(int maxSeconds, Job job) { >- int pauseTime = 10; >- int maxtries = maxSeconds / pauseTime; >- int count = 0; >- while (count++ < maxtries && job.getState() == Job.RUNNING) { >- try { >- Thread.sleep(pauseTime); >- // System.out.println("count: " + count + " max: " + >- // maxtries); >- } >- catch (InterruptedException e) { >- Logger.logException(e); >- } >- } >+ // ensure that it exists on disk >+ File folder = new File(workignLocation.toOSString()); >+ if (!folder.isDirectory()) { >+ try { >+ folder.mkdir(); >+ } >+ catch (SecurityException e) { >+ Logger.logException(this.fName + >+ ": Error while creating state location: " + folder + >+ " This renders the index manager irrevocably broken for this workspace session", >+ e); >+ } >+ } >+ >+ this.fWorkingLocation = workignLocation; >+ } >+ >+ return this.fWorkingLocation; > } > >- private class IndexJobCoordinator extends JobChangeAdapter { >+ /** >+ * @see indexer.internal.indexing.AbstractIndexManager#performAction(byte, byte, org.eclipse.core.resources.IResource, org.eclipse.core.runtime.IPath) >+ */ >+ protected void performAction(byte source, byte action, IResource resource, >+ IPath movePath) { > >- public void aboutToRun(IJobChangeEvent event) { >- Job jobToCoordinate = event.getJob(); >- if (isJobToAvoid(jobToCoordinate)) { >- // job will be rescheduled when the job we >- // are avoiding (eg. build) is done >- getProcessFilesJob().cancel(); >- //System.out.println("cancel:" + jobToCoordinate.getName()); >- } >- } >- >- public void done(IJobChangeEvent event) { >- >- Job jobToCoordinate = event.getJob(); >- if (isJobToAvoid(jobToCoordinate)) { >- if (getProcessFilesJob().getFiles().length > 0) { >- getProcessFilesJob().schedule(500); >- //System.out.println("schedule:" + jobToCoordinate.getName()); >+ //inform the persister of the action unless it come from a full workspace scan >+ if(JSPTranslatorPersister.ACTIVATED && source != AbstractIndexManager.SOURCE_WORKSPACE_SCAN) { >+ switch(action) { >+ case AbstractIndexManager.ACTION_ADD: { >+ JSPTranslatorPersister.persistTranslation(resource); >+ break; >+ } >+ case AbstractIndexManager.ACTION_REMOVE: { >+ JSPTranslatorPersister.removePersistedTranslation(resource); >+ break; >+ } >+ case AbstractIndexManager.ACTION_ADD_MOVE_FROM: { >+ JSPTranslatorPersister.movePersistedTranslation(resource, movePath); >+ break; >+ } >+ case AbstractIndexManager.ACTION_REMOVE_MOVE_TO: { >+ //do nothing, taken care of by AbstractIndexManager.ACTION_ADD_MOVE_FROM >+ break; > } >- >- >- } >- } >- >- private boolean isJobToAvoid(Job jobToCoordinate) { >- boolean result = false; >- if (jobToCoordinate.belongsTo(ResourcesPlugin.FAMILY_AUTO_BUILD) || jobToCoordinate.belongsTo(ResourcesPlugin.FAMILY_MANUAL_BUILD) || jobToCoordinate.belongsTo(ResourcesPlugin.FAMILY_AUTO_REFRESH)) { >- result = true; > } >- return result; >- > } >- >- } >- >- private class JSPResourceChangeListener implements IResourceChangeListener { >- >- >- /** >- * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) >- */ >- public void resourceChanged(IResourceChangeEvent event) { >- >- if (isInitializing()) >- return; >- >- // ignore resource changes if already rebuilding >- if (getIndexState() == S_REBUILDING) >- return; >- // previously canceled, needs entire index rebuild >- if (getIndexState() == S_CANCELED) { >- // rebuildIndex(); >- // just resume indexing >- getProcessFilesJob().schedule(500); >- //System.out.println("schedule: resource changed, previously canceled"); >- return; >- } >- >- IResourceDelta delta = event.getDelta(); >- if (delta != null) { >- // only care about adds or changes right now... >- int kind = delta.getKind(); >- boolean added = (kind & IResourceDelta.ADDED) == IResourceDelta.ADDED; >- boolean changed = (kind & IResourceDelta.CHANGED) == IResourceDelta.CHANGED; >- if (added || changed) { >- >- // only analyze the full (starting at root) delta >- // hierarchy >- if (delta.getFullPath().toString().equals("/")) { //$NON-NLS-1$ >- try { >- JSPResourceVisitor v = getVisitor(); >- // clear from last run >- v.reset(); >- // count files, possibly do this in a job too... >- // don't include PHANTOM resources >- delta.accept(v, false); >- >- // process files from this delta >- IFile[] files = v.getFiles(); >- if (files.length > 0) { >- /* >- * Job change listener should set back to >- * stable when finished >- */ >- setUpdatingState(); >- // processFiles(files); >- indexFiles(files); >- } >- } >- catch (CoreException e) { >- // need to set state here somehow, and reindex >- // otherwise index will be unreliable >- if (DEBUG) >- Logger.logException(e); >- } >- catch (Exception e) { >- // need to set state here somehow, and reindex >- // otherwise index will be unreliable >- if (DEBUG) >- Logger.logException(e); >- } >+ >+ //add any new JSP files to the JDT index using the JSPSearchSupport >+ if(action == AbstractIndexManager.ACTION_ADD || >+ action == AbstractIndexManager.ACTION_ADD_MOVE_FROM) { >+ >+ IFile file = (IFile)resource; //this assumption can be made because of #isResourceToIndex >+ JSPSearchSupport ss = JSPSearchSupport.getInstance(); >+ try { >+ IProject project = file.getProject(); >+ if (project != null) { >+ IJavaProject jproject = JavaCore.create(project); >+ if (jproject.exists()) { >+ ss.addJspFile(file); > } > } >- >+ } >+ catch (Exception e) { >+ String filename = file != null ? file.getFullPath().toString() : ""; //$NON-NLS-1$ >+ Logger.logException("JPSIndexManger: problem indexing:" + filename, e); //$NON-NLS-1$ > } > } >- >- } >- >- IndexWorkspaceJob getIndexingJob() { >- return indexingJob; >- } >- >- ProcessFilesJob getProcessFilesJob() { >- return processFilesJob; > } >- >- boolean isInitializing() { >- return initializing; >- } >- > } >Index: src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchSupport.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchSupport.java,v >retrieving revision 1.22 >diff -u -r1.22 JSPSearchSupport.java >--- src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchSupport.java 26 Feb 2009 05:24:21 -0000 1.22 >+++ src/org/eclipse/jst/jsp/core/internal/java/search/JSPSearchSupport.java 1 Sep 2010 12:23:07 -0000 >@@ -315,10 +315,67 @@ > * @param requestor > * passed in to accept search matches (and do "something" with > * them) >+ * >+ * @deprecated use {@link #search(String, IJavaSearchScope, int, int, int, boolean, SearchRequestor, IProgressMonitor)} > */ > public void search(String searchText, IJavaSearchScope scope, int searchFor, int limitTo, int matchMode, boolean isCaseSensitive, SearchRequestor requestor) { >+ this.search(searchText, scope, searchFor, limitTo, matchMode, isCaseSensitive, >+ requestor, new NullProgressMonitor()); >+ } > >- JSPIndexManager.getInstance().rebuildIndexIfNeeded(); >+ /** >+ * Search for an IJavaElement, constrained by the given parameters. Runs in >+ * a background Job (results may still come in after this method call) >+ * >+ * @param element >+ * @param scope >+ * @param requestor >+ * >+ * @deprecated use {@link #search(IJavaElement, IJavaSearchScope, SearchRequestor, IProgressMonitor)} >+ */ >+ public void search(IJavaElement element, IJavaSearchScope scope, SearchRequestor requestor) { >+ this.search(element, scope, requestor, new NullProgressMonitor()); >+ } >+ >+ /** >+ * Search for an IJavaElement, constrained by the given parameters. Runs in >+ * an IWorkspace runnable (results will be reported by the end of this >+ * method) >+ * >+ * @param element >+ * @param scope >+ * @param requestor >+ */ >+ public void searchRunnable(IJavaElement element, IJavaSearchScope scope, SearchRequestor requestor) { >+ this.searchRunnable(element, scope, requestor, new NullProgressMonitor()); >+ } >+ >+ /** >+ * Perform a java search w/ the given parameters. Runs in a background Job >+ * (results may still come in after this method call) >+ * >+ * @param searchText >+ * the string of text to search on >+ * @param searchFor >+ * IJavaSearchConstants.TYPE, METHOD, FIELD, PACKAGE, etc... >+ * @param limitTo >+ * IJavaSearchConstants.DECLARATIONS, >+ * IJavaSearchConstants.REFERENCES, >+ * IJavaSearchConstants.IMPLEMENTORS, or >+ * IJavaSearchConstants.ALL_OCCURRENCES >+ * @param matchMode >+ * allow * wildcards or not >+ * @param isCaseSensitive >+ * @param requestor >+ * passed in to accept search matches (and do "something" with >+ * them) >+ */ >+ public void search(String searchText, IJavaSearchScope scope, int searchFor, int >+ limitTo, int matchMode, boolean isCaseSensitive, SearchRequestor requestor, >+ IProgressMonitor monitor) { >+ >+ //wait for the index >+ JSPIndexManager.getDefault().waitForConsistant(monitor); > > SearchJob job = new SearchJob(searchText, scope, searchFor, limitTo, matchMode, isCaseSensitive, requestor); > setCanceled(false); >@@ -338,10 +395,12 @@ > * @param scope > * @param requestor > */ >- public void search(IJavaElement element, IJavaSearchScope scope, SearchRequestor requestor) { >- >- JSPIndexManager.getInstance().rebuildIndexIfNeeded(); >+ public void search(IJavaElement element, IJavaSearchScope scope, SearchRequestor requestor, >+ IProgressMonitor monitor) { > >+ //wait for the index >+ JSPIndexManager.getDefault().waitForConsistant(monitor); >+ > SearchJob job = new SearchJob(element, scope, requestor); > setCanceled(false); > job.setUser(true); >@@ -359,9 +418,11 @@ > * @param scope > * @param requestor > */ >- public void searchRunnable(IJavaElement element, IJavaSearchScope scope, SearchRequestor requestor) { >- >- JSPIndexManager.getInstance().rebuildIndexIfNeeded(); >+ public void searchRunnable(IJavaElement element, IJavaSearchScope scope, >+ SearchRequestor requestor, IProgressMonitor monitor) { >+ >+ //wait for the index >+ JSPIndexManager.getDefault().waitForConsistant(monitor); > > SearchRunnable searchRunnable = new SearchRunnable(element, scope, requestor); > try { >#P org.eclipse.jst.jsp.ui >Index: src/org/eclipse/jst/jsp/ui/internal/java/search/ui/JSPQueryParticipant.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.jst.jsp.ui/src/org/eclipse/jst/jsp/ui/internal/java/search/ui/JSPQueryParticipant.java,v >retrieving revision 1.4 >diff -u -r1.4 JSPQueryParticipant.java >--- src/org/eclipse/jst/jsp/ui/internal/java/search/ui/JSPQueryParticipant.java 20 Oct 2009 17:14:55 -0000 1.4 >+++ src/org/eclipse/jst/jsp/ui/internal/java/search/ui/JSPQueryParticipant.java 1 Sep 2010 12:23:08 -0000 >@@ -59,7 +59,7 @@ > SearchRequestor jspRequestor = new JSPSearchRequestor(requestor); > > // pa_TODO need to adapt JavaSearchScope to a JSPSearchScope >- JSPSearchSupport.getInstance().search(element, new JSPSearchScope(), jspRequestor); >+ JSPSearchSupport.getInstance().search(element, new JSPSearchScope(), jspRequestor, monitor); > > } > else if(querySpecification instanceof PatternQuerySpecification) { >@@ -79,7 +79,8 @@ > patternQuery.getLimitTo(), > SearchPattern.R_PATTERN_MATCH, > false, >- jspRequestor); >+ jspRequestor, >+ monitor); > } > } > } >#P org.eclipse.wst.sse.core >Index: META-INF/MANIFEST.MF >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.core/META-INF/MANIFEST.MF,v >retrieving revision 1.35.2.2 >diff -u -r1.35.2.2 MANIFEST.MF >--- META-INF/MANIFEST.MF 16 Aug 2010 17:36:29 -0000 1.35.2.2 >+++ META-INF/MANIFEST.MF 1 Sep 2010 12:23:09 -0000 >@@ -7,6 +7,7 @@ > Bundle-Vendor: %providerName > Bundle-Localization: plugin > Export-Package: org.eclipse.wst.sse.core, >+ org.eclipse.wst.sse.core.indexing, > org.eclipse.wst.sse.core.internal;x-friends:="org.eclipse.wst.dtd.core,org.eclipse.wst.dtd.ui,org.eclipse.wst.sse.ui,org.eclipse.wst.xml.core,org.eclipse.wst.xml.ui,org.eclipse.wst.xsd.core,org.eclipse.wst.xsd.ui", > org.eclipse.wst.sse.core.internal.cleanup;x-friends:="org.eclipse.wst.dtd.core,org.eclipse.wst.dtd.ui,org.eclipse.wst.sse.ui,org.eclipse.wst.xml.core,org.eclipse.wst.xml.ui,org.eclipse.wst.xsd.core,org.eclipse.wst.xsd.ui", > org.eclipse.wst.sse.core.internal.document;x-friends:="org.eclipse.wst.dtd.core,org.eclipse.wst.dtd.ui,org.eclipse.wst.sse.ui,org.eclipse.wst.xml.core,org.eclipse.wst.xml.ui,org.eclipse.wst.xsd.core,org.eclipse.wst.xsd.ui", >Index: src/org/eclipse/wst/sse/core/indexing/AbstractIndexManager.java >=================================================================== >RCS file: src/org/eclipse/wst/sse/core/indexing/AbstractIndexManager.java >diff -N src/org/eclipse/wst/sse/core/indexing/AbstractIndexManager.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/wst/sse/core/indexing/AbstractIndexManager.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,1665 @@ >+/******************************************************************************* >+ * Copyright (c) 2010 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.wst.sse.core.indexing; >+ >+import java.io.BufferedInputStream; >+import java.io.BufferedOutputStream; >+import java.io.DataInputStream; >+import java.io.DataOutputStream; >+import java.io.File; >+import java.io.FileInputStream; >+import java.io.FileNotFoundException; >+import java.io.FileOutputStream; >+import java.io.IOException; >+import java.util.Iterator; >+import java.util.LinkedHashMap; >+import java.util.Map; >+ >+import org.eclipse.core.resources.IFile; >+import org.eclipse.core.resources.IResource; >+import org.eclipse.core.resources.IResourceChangeEvent; >+import org.eclipse.core.resources.IResourceChangeListener; >+import org.eclipse.core.resources.IResourceDelta; >+import org.eclipse.core.resources.IResourceDeltaVisitor; >+import org.eclipse.core.resources.IResourceProxy; >+import org.eclipse.core.resources.IResourceProxyVisitor; >+import org.eclipse.core.resources.ISaveParticipant; >+import org.eclipse.core.resources.ResourcesPlugin; >+import org.eclipse.core.runtime.CoreException; >+import org.eclipse.core.runtime.IPath; >+import org.eclipse.core.runtime.IProgressMonitor; >+import org.eclipse.core.runtime.ISafeRunnable; >+import org.eclipse.core.runtime.IStatus; >+import org.eclipse.core.runtime.Path; >+import org.eclipse.core.runtime.SafeRunner; >+import org.eclipse.core.runtime.Status; >+import org.eclipse.core.runtime.SubMonitor; >+import org.eclipse.core.runtime.jobs.Job; >+import org.eclipse.osgi.util.NLS; >+import org.eclipse.wst.sse.core.internal.Logger; >+import org.eclipse.wst.sse.core.internal.SSECoreMessages; >+ >+/** >+ * <p>Provides a generic for writing a resource index manager. It is important >+ * to note that this only provides the framework for managing an index, not actually >+ * indexing. The subtle difference is that the manager is in charge of paying attention >+ * to all of the resource actions that take place in the workspace and filtering those >+ * actions down to simple actions that need to be performed on whatever index this manger >+ * is managing.</p> >+ * >+ * <p>The manger does its very best to make sure the index is always consistent, even if >+ * resource events take place when the manager is not running. In the event that the >+ * manager determines it has missed, loosed, or corrupted any resource change events >+ * that have occurred before, during, or after its activation or de-activation then the >+ * manager will inspect the entire workspace to insure the index it is managing is >+ * Consistent.</p> >+ * >+ */ >+public abstract class AbstractIndexManager { >+ >+ /** Default time to wait for other tasks to finish */ >+ private static final int WAIT_TIME = 300; >+ >+ /** >+ * <p>Used to report progress on jobs where the total work to complete is unknown. >+ * The created effect is a progress bar that moves but that will never complete.</p> >+ */ >+ private static final int UNKNOWN_WORK = 100; >+ >+ /** The amount of events to batch up before sending them off to the processing job*/ >+ private static final int BATCH_UP_AMONT = 100; >+ >+ /** If this file exists then a full workspace re-processing is needed */ >+ private static final String RE_PROCESS_FILE_NAME = ".re-process"; //$NON-NLS-1$ >+ >+ /** Common error message to log */ >+ private static final String LOG_ERROR_INDEX_INVALID = >+ "Index may become invalid, incomplete, or enter some other inconsistent state."; //$NON-NLS-1$ >+ >+ /** State: manager is stopped */ >+ private static final byte STATE_DISABLED = 0; >+ >+ /** State: manager is running */ >+ private static final byte STATE_ENABLED = 1; >+ >+ /** Action: add to index */ >+ protected static final byte ACTION_ADD = 0; >+ >+ /** Action: remove from index */ >+ protected static final byte ACTION_REMOVE = 1; >+ >+ /** Action: add to index caused by move operation */ >+ protected static final byte ACTION_ADD_MOVE_FROM = 2; >+ >+ /** Action: remove from index caused by move operation */ >+ protected static final byte ACTION_REMOVE_MOVE_TO = 3; >+ >+ /** Source: action originated from resource change event */ >+ protected static final byte SOURCE_RESROUCE_CHANGE = 0; >+ >+ /** Source: action originated from workspace scan */ >+ protected static final byte SOURCE_WORKSPACE_SCAN = 1; >+ >+ /** Source: action originated from saved state */ >+ protected static final byte SOURCE_SAVED_STATE = 2; >+ >+ /** Source: preserved resources to index */ >+ protected static final byte SOURCE_PRESERVED_RESOURCES_TO_INDEX = 3; >+ >+ /** the name of this index manager */ >+ protected String fName; >+ >+ /** {@link IResourceChangeListener} to listen for file changes */ >+ private ResourceChangeListener fResourceChangeListener; >+ >+ /** The {@link Job} that does all of the indexing */ >+ private ResourceEventProcessingJob fResourceEventProcessingJob; >+ >+ /** A {@link Job} to search the workspace for all files */ >+ private Job fWorkspaceVisitorJob; >+ >+ /** >+ * <p>Current state of the manager</p> >+ * >+ * @see #STATE_DISABLED >+ * @see #STATE_ENABLED >+ */ >+ private volatile byte fState; >+ >+ /** used to prevent manager from starting and stopping at the same time */ >+ private Object fStartStopLock = new Object(); >+ >+ /** <code>true</code> if the manger is currently starting, <code>false</code> otherwise */ >+ private boolean fStarting; >+ >+ /** >+ * <p>Creates the manager with a given name.</p> >+ * >+ * @param name This will be pre-pended to progress reporting messages and thus should >+ * be translated >+ */ >+ protected AbstractIndexManager(String name) { >+ this.fName = name; >+ this.fState = STATE_DISABLED; >+ this.fResourceChangeListener = new ResourceChangeListener(); >+ this.fResourceEventProcessingJob = new ResourceEventProcessingJob(); >+ this.fStarting = false; >+ } >+ >+ /** >+ * <p>Starts up the {@link AbstractIndexManager}. If a {@link IResourceDelta} >+ * is provided then it is assumed that all other files in the workspace >+ * have already been index and thus only those in the provided >+ * {@link IResourceDelta} will be processed. Else if the provided >+ * {@link IResourceDelta} is <code>null</code> it is assumed no files >+ * have been indexed yet so the entire workspace will be searched for >+ * files to be indexed.</p> >+ * >+ * <p>If {@link IResourceDelta} is provided this will block until that delta >+ * has finished processing. If no {@link IResourceDelta} provided then a >+ * separate job will be created to process the entire workspace and this method >+ * will return without waiting for that job to complete</p> >+ * >+ * <p>Will block until {@link #stop()} has finished running if it is >+ * currently running</p> >+ * >+ * @param savedStateDelta the delta from a saved state, if <code>null</code> >+ * then the entire workspace will be searched for files to index, else >+ * only files in this {@link IResourceDelta} will be indexed >+ * @param monitor This action can not be canceled but this monitor will be used >+ * to report progress >+ */ >+ public final void start(IResourceDelta savedStateDelta, IProgressMonitor monitor) { >+ SubMonitor progress = SubMonitor.convert(monitor); >+ synchronized (this.fStartStopLock) { >+ this.fStarting = true; >+ >+ if(this.fState == STATE_DISABLED) { >+ //report status >+ progress.beginTask(this.fName + ": " + SSECoreMessages.IndexManager_starting, //$NON-NLS-1$ >+ 2); >+ >+ //start listening for resource change events >+ this.fResourceChangeListener.start(); >+ >+ //check to see if a full re-index is required >+ boolean forcedFullReIndexNeeded = this.isForcedFullReIndexNeeded(); >+ >+ /* start the indexing job only loading preserved state if not doing full index >+ * if failed loading preserved state then force full re-index >+ */ >+ forcedFullReIndexNeeded = !this.fResourceEventProcessingJob.start(!forcedFullReIndexNeeded, >+ progress.newChild(1)); >+ progress.setWorkRemaining(1); >+ >+ //don't bother processing saved delta if forced full re-index is needed >+ boolean stillNeedFullReIndex = forcedFullReIndexNeeded; >+ if(!forcedFullReIndexNeeded) { >+ //if there is a delta attempt to process it >+ if(savedStateDelta != null) { >+ stillNeedFullReIndex = false; >+ try { >+ //deal with reporting progress >+ SubMonitor savedStateProgress = progress.newChild(1, SubMonitor.SUPPRESS_NONE); >+ savedStateProgress.setTaskName( >+ this.fName + ": " + SSECoreMessages.IndexManager_starting + ": " + //$NON-NLS-1$ //$NON-NLS-2$ >+ SSECoreMessages.IndexManager_processing_deferred_resource_changes); >+ >+ //process delta >+ ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(savedStateProgress, >+ AbstractIndexManager.SOURCE_SAVED_STATE); >+ savedStateDelta.accept(visitor); >+ >+ //process any remaining batched up resources to index >+ visitor.processBatchedResourceEvents(); >+ } catch (CoreException e) { >+ stillNeedFullReIndex = true; >+ Logger.logException(this.fName + ": Could not process saved state. " + //$NON-NLS-1$ >+ "Forced to do a full workspace re-index.", e); //$NON-NLS-1$ >+ } >+ } >+ } >+ progress.worked(1); >+ >+ //if need to process the entire workspace do so in another job >+ if(stillNeedFullReIndex){ >+ this.fWorkspaceVisitorJob = new WorkspaceVisitorJob(); >+ this.fWorkspaceVisitorJob.schedule(); >+ } >+ >+ //update state >+ this.fState = STATE_ENABLED; >+ } >+ this.fStarting = false; >+ } >+ } >+ >+ /** >+ * <p>Safely shuts down the manager.</p> >+ * >+ * <p>This will block until the {@link #start(IResourceDelta, IProgressMonitor)} has >+ * finished (if running). Also until the current resource event has finished being >+ * processed. Finally it will block until the events still to be processed by >+ * the processing job have been preserved to be processed on the next call to >+ * {@link #start(IResourceDelta, IProgressMonitor)}.</p> >+ * >+ * <p>If at any point during this shut down processes something goes wrong the >+ * manager will be sure that on the next call to {@link #start(IResourceDelta, IProgressMonitor)} >+ * the entire workspace will be re-processed.</p> >+ * >+ * @throws InterruptedException >+ */ >+ public final void stop() throws InterruptedException { >+ synchronized (this.fStartStopLock) { >+ if(this.fState != STATE_DISABLED) { >+ >+ //stop listening for events, and wait for the current event to finish >+ this.fResourceChangeListener.stop(); >+ >+ // if currently visiting entire workspace, give up and try again next load >+ boolean forceFullReIndexNextStart = false; >+ if(this.fWorkspaceVisitorJob != null) { >+ if (this.fWorkspaceVisitorJob.getState() != Job.NONE) { >+ this.fWorkspaceVisitorJob.cancel(); >+ >+ this.forceFullReIndexNextStart(); >+ forceFullReIndexNextStart = true; >+ } >+ } >+ >+ //stop the indexing job, only preserve if not already forcing a re-index >+ forceFullReIndexNextStart = !this.fResourceEventProcessingJob.stop(!forceFullReIndexNextStart); >+ >+ //if preserving failed, then force re-index >+ if(forceFullReIndexNextStart) { >+ this.forceFullReIndexNextStart(); >+ } >+ >+ //update status >+ this.fState = STATE_DISABLED; >+ } >+ } >+ } >+ >+ /** >+ * <p>Should be called by an client of the index this manger manages before the index >+ * is accessed, assuming the client wants an index consistent with the latest >+ * resource changes.</p> >+ * >+ * <p>The supplied monitor will be used to supply user readable progress as the manager >+ * insures the index has been given all the latest resource events. This monitor >+ * maybe canceled, but if it is the state of the index is not guaranteed to be >+ * consistent with the latest resource change events.</p> >+ * >+ * @param monitor Used to report user readable progress as the manager insures the >+ * index is consistent with the latest resource events. This monitor can be canceled >+ * to stop waiting for consistency but then no guaranty is made about the consistency >+ * of the index in relation to un-processed resource changes >+ * >+ * @return <code>true</code> if the wait finished successfully and the manger is consistent, >+ * <code>false</code> otherwise, either an error occurred while waiting for the manager >+ * or the monitor was canceled >+ * >+ * @throws InterruptedException This can happen when waiting for other jobs >+ */ >+ public final boolean waitForConsistant(IProgressMonitor monitor) { >+ boolean success = true; >+ boolean interupted = false; >+ SubMonitor progress = SubMonitor.convert(monitor); >+ >+ //set up the progress of waiting >+ int remainingWork = 4; >+ progress.beginTask(NLS.bind(SSECoreMessages.IndexManager_Waiting_for_0, this.fName), >+ remainingWork); >+ >+ //wait for start up >+ if(this.fStarting && !monitor.isCanceled()) { >+ SubMonitor startingProgress = progress.newChild(1); >+ startingProgress.subTask(SSECoreMessages.IndexManager_starting); >+ while(this.fStarting && !monitor.isCanceled()) { >+ //this creates a never ending progress that still moves forward >+ startingProgress.setWorkRemaining(UNKNOWN_WORK); >+ startingProgress.newChild(1).worked(1); >+ try { >+ Thread.sleep(WAIT_TIME); >+ } catch (InterruptedException e) { >+ interupted = true; >+ } >+ } >+ } >+ progress.setWorkRemaining(--remainingWork); >+ >+ //wait for workspace visiting job >+ if(this.fWorkspaceVisitorJob != null && this.fWorkspaceVisitorJob.getState() != Job.NONE && !monitor.isCanceled()) { >+ SubMonitor workspaceVisitorProgress = progress.newChild(1); >+ workspaceVisitorProgress.subTask(SSECoreMessages.IndexManager_Processing_entire_workspace_for_the_first_time); >+ while(this.fWorkspaceVisitorJob.getState() != Job.NONE && !monitor.isCanceled()) { >+ //this creates a never ending progress that still moves forward >+ workspaceVisitorProgress.setWorkRemaining(UNKNOWN_WORK); >+ workspaceVisitorProgress.newChild(1).worked(1); >+ try { >+ Thread.sleep(WAIT_TIME); >+ } catch (InterruptedException e) { >+ interupted = true; >+ } >+ } >+ } >+ progress.setWorkRemaining(--remainingWork); >+ >+ //wait for the current resource event >+ if(this.fResourceChangeListener.isProcessingEvents() && !monitor.isCanceled()) { >+ SubMonitor workspaceVisitorProgress = progress.newChild(1); >+ workspaceVisitorProgress.subTask(SSECoreMessages.IndexManager_processing_recent_resource_changes); >+ while(this.fResourceChangeListener.isProcessingEvents() && !monitor.isCanceled()) { >+ workspaceVisitorProgress.setWorkRemaining(UNKNOWN_WORK); >+ workspaceVisitorProgress.newChild(1).worked(1); >+ try { >+ this.fResourceChangeListener.waitForCurrentEvent(WAIT_TIME); >+ } catch (InterruptedException e) { >+ interupted = true; >+ } >+ } >+ } >+ progress.setWorkRemaining(--remainingWork); >+ >+ //wait for all files to be indexed >+ if(this.fResourceEventProcessingJob.getNumResourceEventsToProcess() != 0 && !monitor.isCanceled()) { >+ SubMonitor indexingProgress = progress.newChild(1); >+ int prevNumResrouces; >+ int numResources = this.fResourceEventProcessingJob.getNumResourceEventsToProcess(); >+ while(numResources != 0 && !monitor.isCanceled()) { >+ //update the progress indicator >+ indexingProgress.subTask(AbstractIndexManager.this.fName + ": " + //$NON-NLS-1$ >+ NLS.bind(SSECoreMessages.IndexManager_Indexing_0_Files, >+ "" + numResources)); //$NON-NLS-1$ >+ indexingProgress.setWorkRemaining(numResources); >+ prevNumResrouces = numResources; >+ numResources = this.fResourceEventProcessingJob.getNumResourceEventsToProcess(); >+ int numProcessed = prevNumResrouces - numResources; >+ indexingProgress.worked(numProcessed > 0 ? numProcessed : 0); >+ >+ //give the index some time to do some indexing >+ try { >+ this.fResourceEventProcessingJob.waitForConsistant(WAIT_TIME); >+ } catch (InterruptedException e) { >+ interupted = true; >+ } >+ } >+ } >+ progress.setWorkRemaining(--remainingWork); >+ >+ if(monitor.isCanceled()) { >+ success = false; >+ } >+ >+ //reset the interrupted flag if we were interrupted >+ if(interupted) { >+ Thread.currentThread().interrupt(); >+ } >+ >+ return success; >+ } >+ >+ /** >+ * <p>Used to determine if an {@link IResource} with the given >+ * type and name should be processed by this index manager</p> >+ * >+ * @param type see {@link IResource#getType()} >+ * @param name the name of the resource >+ * >+ * @return <code>true</code> if this index manager processes resources >+ * of the given <code>type</code> with the given <code>name</code>, >+ * <code>false</code> otherwise >+ */ >+ protected abstract boolean isResourceToIndex(int type, String name); >+ >+ /** >+ * <p>Called for each {@link ResourceEvent} gathered by the various sources and processed >+ * by the {@link ResourceEventProcessingJob}. The implementation of this method >+ * should use the given information to update the index this manger is managing.</p> >+ * >+ * @param source The source that reported this resource event >+ * @param action The action to be taken on the given <code>resource</code> >+ * @param resource The index should perform the given <code>action</code> on this >+ * resource >+ * @param movePath If the given <code>action</code> is {@link AbstractIndexManager#ACTION_ADD_MOVE_FROM} >+ * or {@link AbstractIndexManager#ACTION_REMOVE_MOVE_TO} then this field will not be >+ * null and reports the path the given <code>resource</code> was either moved from or >+ * moved to respectively. >+ * >+ * @see AbstractIndexManager#SOURCE_RESROUCE_CHANGE >+ * @see AbstractIndexManager#SOURCE_SAVED_STATE >+ * @see AbstractIndexManager#SOURCE_WORKSPACE_SCAN >+ * @see AbstractIndexManager#SOURCE_PRESERVED_RESOURCES_TO_INDEX >+ * >+ * @see AbstractIndexManager#ACTION_ADD >+ * @see AbstractIndexManager#ACTION_REMOVE >+ * @see AbstractIndexManager#ACTION_ADD_MOVE_FROM >+ * @see AbstractIndexManager#ACTION_REMOVE_MOVE_TO >+ */ >+ protected abstract void performAction(byte source, byte action, IResource resource, >+ IPath movePath); >+ >+ /** >+ * <p>Gets the working location of the manager. This is where any relevant >+ * state can be persisted.</p> >+ * >+ * @return the working location of the manager >+ */ >+ protected abstract IPath getWorkingLocation(); >+ >+ /** >+ * <p>Determines if a resource should be visited or not while >+ * looking for files to index. If a resource should not be >+ * visited it is assumed its children should not be visited either.</p> >+ * >+ * <p>Implementers may override. Default is to ignore resources >+ * starting with a period.</p> >+ * >+ * @param resourceName name of the resource to determine if it >+ * should be visited or not >+ * >+ * @return <code>true</code> if the resource should be visited, >+ * <code>false</code> otherwise >+ */ >+ protected boolean shouldVisit(String resourceName) { >+ return !resourceName.startsWith(".");//$NON-NLS-1$ >+ } >+ >+ /** >+ * <p>Next time the manager starts up force a full workspace index</p> >+ */ >+ private void forceFullReIndexNextStart() { >+ IPath reIndexPath = >+ AbstractIndexManager.this.getWorkingLocation().append(RE_PROCESS_FILE_NAME); >+ File file = new File(reIndexPath.toOSString()); >+ try { >+ file.createNewFile(); >+ } catch (IOException e) { >+ Logger.logException(this.fName + ": Could not create file to tell manager to" + //$NON-NLS-1$ >+ " do a full re-index on next load. " + //$NON-NLS-1$ >+ AbstractIndexManager.LOG_ERROR_INDEX_INVALID, e); >+ } >+ } >+ >+ /** >+ * @return <code>true</code> if a full workspace index is needed as dictated by >+ * a previous call to {@link #forceFullReIndexNextStart()}, <code>false</code> >+ * otherwise >+ */ >+ private boolean isForcedFullReIndexNeeded() { >+ boolean forcedFullReIndexNeeded = false; >+ IPath reIndexPath = >+ AbstractIndexManager.this.getWorkingLocation().append(RE_PROCESS_FILE_NAME); >+ File file = new File(reIndexPath.toOSString()); >+ if(file.exists()) { >+ file.delete(); >+ forcedFullReIndexNeeded = true; >+ } >+ >+ return forcedFullReIndexNeeded; >+ } >+ >+ /** >+ * <p>A system {@link Job} used to visit all of the files in the workspace >+ * looking for files to index.</p> >+ * >+ * <p>This should only have to be done once per workspace on the first load, >+ * but if it fails or a SavedState can not be retrieved on a subsequent >+ * workspace load then this will have to be done again.</p> >+ */ >+ private class WorkspaceVisitorJob extends Job { >+ /** >+ * <p>Default constructor that sets up this job as a system job</p> >+ */ >+ protected WorkspaceVisitorJob() { >+ super(AbstractIndexManager.this.fName + ": " + //$NON-NLS-1$ >+ SSECoreMessages.IndexManager_Processing_entire_workspace_for_the_first_time); >+ >+ this.setUser(false); >+ this.setSystem(true); >+ this.setPriority(Job.LONG); >+ } >+ >+ /** >+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) >+ */ >+ protected IStatus run(IProgressMonitor monitor) { >+ try { >+ //update status >+ monitor.beginTask(AbstractIndexManager.this.fName + ": " + //$NON-NLS-1$ >+ SSECoreMessages.IndexManager_Processing_entire_workspace_for_the_first_time, >+ IProgressMonitor.UNKNOWN); >+ >+ //visit the workspace >+ WorkspaceVisitor visitor = new WorkspaceVisitor(monitor); >+ ResourcesPlugin.getWorkspace().getRoot().accept(visitor, IResource.NONE); >+ >+ //process any remaining batched up resources to index >+ visitor.processBatchedResourceEvents(); >+ } catch(CoreException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Failed visiting entire workspace for initial index. " + //$NON-NLS-1$ >+ AbstractIndexManager.LOG_ERROR_INDEX_INVALID, e); >+ } >+ >+ IStatus status; >+ if(monitor.isCanceled()) { >+ status = Status.CANCEL_STATUS; >+ } else { >+ status = Status.OK_STATUS; >+ } >+ >+ return status; >+ } >+ >+ /** >+ * <p>An {@link IResourceProxyVisitor} used to visit all of the files in the >+ * workspace looking for files to add to the index.</p> >+ * >+ * <p><b>NOTE: </b>After this visitor is used {@link WorkspaceVisitor#processBatchedResourceEvents() >+ * must be called to flush out the last of the {@link ResourceEvent}s produced >+ * by this visitor.</p> >+ */ >+ private class WorkspaceVisitor implements IResourceProxyVisitor { >+ /** {@link IProgressMonitor} used to report status and check for cancellation */ >+ private SubMonitor fProgress; >+ >+ /** >+ * {@link Map}<{@link IResource}, {@link ResourceEvent}> >+ * <p>Map of resources events created and batched up by this visitor. >+ * These events are periodical be sent off to the >+ * {@link ResourceEventProcessingJob} but need to be sent off >+ * one final time after this visitor finishes it work.</p> >+ * >+ * @see #processBatchedResourceEvents() >+ */ >+ private Map fBatchedResourceEvents; >+ >+ /** >+ * <p>Default constructor</p> >+ * @param monitor used to report status and allow this visitor to be canceled >+ */ >+ protected WorkspaceVisitor(IProgressMonitor monitor) { >+ this.fProgress = SubMonitor.convert(monitor); >+ this.fBatchedResourceEvents = new LinkedHashMap(BATCH_UP_AMONT); >+ } >+ >+ /** >+ * <p>As long as the monitor is not canceled visit each file in the workspace >+ * that should be visited.</p> >+ * >+ * @see org.eclipse.core.resources.IResourceProxyVisitor#visit(org.eclipse.core.resources.IResourceProxy) >+ * @see AbstractIndexManager#shouldVisit(String) >+ */ >+ public boolean visit(IResourceProxy proxy) throws CoreException { >+ this.fProgress.subTask(proxy.getName()); >+ >+ boolean visitChildren = false; >+ >+ /* if not canceled or a hidden resource then process file >+ * else don't visit children >+ */ >+ if(!this.fProgress.isCanceled() && shouldVisit(proxy.getName())) { >+ if(isResourceToIndex(proxy.getType(), proxy.getName())) { >+ >+ //add the file to be indexed >+ IFile file = (IFile) proxy.requestResource(); >+ if(file.exists()) { >+ this.fBatchedResourceEvents.put(file, new ResourceEvent( >+ AbstractIndexManager.SOURCE_WORKSPACE_SCAN, >+ AbstractIndexManager.ACTION_ADD, >+ null)); >+ } >+ } >+ >+ visitChildren = true; >+ } else { >+ visitChildren = false; >+ } >+ >+ //batch up resource changes before sending them out >+ if(this.fBatchedResourceEvents.size() >= BATCH_UP_AMONT) { >+ this.processBatchedResourceEvents(); >+ } >+ >+ return visitChildren; >+ } >+ >+ /** >+ * <p>Sends any batched up resource events created by this visitor to the >+ * {@link ResourceEventProcessingJob}.<p> >+ * >+ * <p><b>NOTE:</b> This will be called every so often as the visitor is >+ * visiting resources but needs to be called a final time by the user of >+ * this visitor to be sure the final events are sent off</p> >+ */ >+ protected void processBatchedResourceEvents() { >+ AbstractIndexManager.this.fResourceEventProcessingJob.addResourceEvents( >+ this.fBatchedResourceEvents); >+ this.fBatchedResourceEvents.clear(); >+ } >+ } >+ } >+ >+ /** >+ * <p>Used to listen to resource change events in the workspace. These events >+ * are batched up and then passed onto the {@link ResourceEventProcessingJob}.</p> >+ */ >+ private class ResourceChangeListener implements IResourceChangeListener { >+ /** >+ * <p>The number of events currently being processed by this listener.</p> >+ * <p>Use the {@link #fEventsBeingProcessedLock} when reading or writing this field</p> >+ * >+ * @see #fEventsBeingProcessedLock >+ */ >+ private volatile int fEventsBeingProcessed; >+ >+ /** >+ * Lock to use when reading or writing {@link #fEventsBeingProcessed} >+ * >+ * @see #fEventsBeingProcessed >+ */ >+ private final Object fEventsBeingProcessedLock = new Object(); >+ >+ /** >+ * <p>Current state of this listener</p> >+ * >+ * @see AbstractIndexManager#STATE_DISABLED >+ * @see AbstractIndexManager#STATE_ENABLED >+ */ >+ private volatile byte fState; >+ >+ /** >+ * <p>Default constructor</p> >+ */ >+ protected ResourceChangeListener() { >+ this.fState = STATE_DISABLED; >+ this.fEventsBeingProcessed = 0; >+ } >+ >+ /** >+ * <p>Start listening for resource change events</p> >+ */ >+ protected void start() { >+ this.fState = STATE_ENABLED; >+ ResourcesPlugin.getWorkspace().addResourceChangeListener(this); >+ } >+ >+ /** >+ * <p>Stop listening for resource change events and if already processing >+ * an event then wait for that processing to finish</p> >+ * >+ * @throws InterruptedException waiting for a current event to finish processing >+ * could be interrupted >+ */ >+ protected void stop() throws InterruptedException { >+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); >+ >+ //wait indefinitely for current event to finish processing >+ this.waitForCurrentEvent(0); >+ >+ this.fState = STATE_DISABLED; >+ } >+ >+ /** >+ * <p>Blocks until either the current resource event has been processed or >+ * until the given timeout has passed.</p> >+ * >+ * @param timeout block until either this timeout elapses (0 means never to timeout) >+ * or the current resource change event finishes being processed >+ * >+ * @throws InterruptedException This can happen when waiting for a lock >+ */ >+ protected void waitForCurrentEvent(int timeout) throws InterruptedException { >+ synchronized (this.fEventsBeingProcessedLock) { >+ if(this.fEventsBeingProcessed != 0) { >+ this.fEventsBeingProcessedLock.wait(timeout); >+ } >+ } >+ } >+ >+ /** >+ * @return <code>true</code> if this listener is currently processing any >+ * events, <code>false</code> otherwise. >+ */ >+ protected boolean isProcessingEvents() { >+ return this.fEventsBeingProcessed != 0; >+ } >+ >+ /** >+ * <p>Process a resource change event. If it is a pre-close or pre-delete then >+ * the {@link ResourceEventProcessingJob} is paused so it does not try to >+ * process resources that are about to be deleted. The {@link ResourceDeltaVisitor} >+ * is used to actually process the event.</p> >+ * >+ * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) >+ * @see ResourceDeltaVisitor >+ */ >+ public void resourceChanged(IResourceChangeEvent event) { >+ try { >+ //update the number of events being processed >+ synchronized (this.fEventsBeingProcessedLock) { >+ ++this.fEventsBeingProcessed; >+ } >+ >+ if(this.fState == STATE_ENABLED) { >+ switch(event.getType()) { >+ case IResourceChangeEvent.PRE_CLOSE: >+ case IResourceChangeEvent.PRE_DELETE:{ >+ //pre-close or pre-delete pause the persister job so it does not interfere >+ AbstractIndexManager.this.fResourceEventProcessingJob.pause(); >+ break; >+ } >+ case IResourceChangeEvent.POST_BUILD: >+ case IResourceChangeEvent.POST_CHANGE: { >+ //post change start up the indexer job and process the delta >+ AbstractIndexManager.this.fResourceEventProcessingJob.unPause(); >+ >+ // only analyze the full (starting at root) delta hierarchy >+ IResourceDelta delta = event.getDelta(); >+ if (delta != null && delta.getFullPath().toString().equals("/")) { //$NON-NLS-1$ >+ try { >+ //use visitor to visit all children >+ ResourceDeltaVisitor visitor = new ResourceDeltaVisitor( >+ AbstractIndexManager.SOURCE_RESROUCE_CHANGE); >+ delta.accept(visitor, false); >+ >+ //process any remaining batched up resources to index >+ visitor.processBatchedResourceEvents(); >+ } catch (CoreException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Failed visiting resrouce change delta. " + //$NON-NLS-1$ >+ AbstractIndexManager.LOG_ERROR_INDEX_INVALID, e); >+ } >+ } >+ break; >+ } >+ } >+ } else { >+ Logger.log(Logger.ERROR, "A resource change event came in after " + >+ AbstractIndexManager.this.fName + " shut down. This should never " + >+ "ever happen, but if it does the index may now be inconsistant."); >+ } >+ } finally { >+ //no matter how we exit be sure to update the number of events being processed >+ synchronized (this.fEventsBeingProcessedLock) { >+ --this.fEventsBeingProcessed; >+ >+ //if currently not events being processed, then notify >+ if(this.fEventsBeingProcessed == 0) { >+ this.fEventsBeingProcessedLock.notifyAll(); >+ } >+ } >+ } >+ } >+ } >+ >+ /** >+ * <p>Used to visit {@link IResourceDelta}s from both the {@link IResourceChangeListener} >+ * and from a {@link ISaveParticipant} given to {@link AbstractIndexManager#start(IResourceDelta, IProgressMonitor)}. >+ * The resource events are batched into groups of {@link AbstractIndexManager#BATCH_UP_AMONT} >+ * before being passed onto the {@link ResourceEventProcessingJob}.</p> >+ * >+ * <p><b>NOTE 1: </b> This class is intended for one time use, thus a new instance should >+ * be instantiated each time this visitor is needed to process a new {@link IResourceDelta}.</p> >+ * >+ * <p><b>NOTE 2: </b> Be sure to call {@link ResourceDeltaVisitor#processBatchedResourceEvents()} >+ * after using this visitor to be sure any remaining events get passed onto the >+ * {@link ResourceEventProcessingJob}.</p> >+ * >+ * @see ResourceDeltaVisitor#processBatchedResourceEvents() >+ */ >+ private class ResourceDeltaVisitor implements IResourceDeltaVisitor { >+ /** {@link IProgressMonitor} used to report status */ >+ private SubMonitor fProgress; >+ >+ /** >+ * <p>The source that should be used when sending resource events to the >+ * {@link ResourceEventProcessingJob}.</p> >+ * >+ * @see AbstractIndexManager#SOURCE_SAVED_STATE >+ * @see AbstractIndexManager#SOURCE_RESROUCE_CHANGE >+ */ >+ private byte fSource; >+ >+ /** >+ * <p>Due to the nature of a visitor it has no way of knowing the total amount >+ * of work it has to do but it can start to predict it based on the number of >+ * children of each event it processes and whether it plans on visiting those >+ * children</p> >+ */ >+ private int fPredictedWorkRemaining; >+ >+ /** >+ * {@link Map}<{@link IResource}, {@link ResourceEvent}> >+ * <p>Map of resources events created and batched up by this visitor. >+ * These events are periodical be sent off to the >+ * {@link ResourceEventProcessingJob} but need to be sent off >+ * one final time after this visitor finishes it work.</p> >+ * >+ * @see #processBatchedResourceEvents() >+ */ >+ private Map fBatchedResourceEvents; >+ >+ /** >+ * <p>Creates a visitor that will create resource events based on the resources >+ * it visits and using the given source as the source of the events.</p> >+ * >+ * @param source The source of the events that should be used when creating >+ * resource events from visited resources >+ * >+ * @see AbstractIndexManager#SOURCE_RESROUCE_CHANGE >+ * @see AbstractIndexManager#SOURCE_SAVED_STATE >+ */ >+ protected ResourceDeltaVisitor(byte source) { >+ this(SubMonitor.convert(null), source); >+ } >+ >+ /** >+ * <p>Creates a visitor that will create resource events based on the resources >+ * it visits and using the given source as the source of the events and >+ * report its status to the given progress as best it can as it visits >+ * resources.</p> >+ * >+ * <p><b>NOTE:</b> While the {@link SubMonitor} is provided to report status the >+ * visitor will not honor any cancellation requests.</p> >+ * >+ * @param progress Used to report status. This visitor can <b>not</b> be >+ * canceled >+ * @param source The source of the events that should be used when creating >+ * resource events from visited resources >+ * >+ * @see AbstractIndexManager#SOURCE_RESROUCE_CHANGE >+ * @see AbstractIndexManager#SOURCE_SAVED_STATE >+ */ >+ protected ResourceDeltaVisitor(SubMonitor progress, byte source) { >+ this.fProgress = progress; >+ this.fSource = source; >+ this.fBatchedResourceEvents = new LinkedHashMap(BATCH_UP_AMONT); >+ this.fPredictedWorkRemaining = 1; >+ } >+ >+ /** >+ * <p>Transforms each {@link IResourceDelta} into a {@link ResourceEvent}. >+ * Batches up these {@link ResourceEvent}s and then passes them onto the >+ * {@link ResourceEventProcessingJob}.</p> >+ * >+ * <p><b>NOTE 2: </b> Be sure to call {@link ResourceDeltaVisitor#processBatchedResourceEvents()} >+ * after using this visitor to be sure any remaining events get passed onto the >+ * {@link ResourceEventProcessingJob}.</p> >+ * >+ * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta) >+ * @see #processBatchedResourceEvents() >+ */ >+ public boolean visit(IResourceDelta delta) throws CoreException { >+ //report status >+ this.fProgress.subTask( >+ NLS.bind(SSECoreMessages.IndexManager_0_resources_to_go, "" + fPredictedWorkRemaining) + //$NON-NLS-1$ >+ ": " + delta.getFullPath().toString()); //$NON-NLS-1$ >+ >+ //process delta if resource not hidden >+ boolean visitChildren = false; >+ IResource resource = delta.getResource(); >+ if(shouldVisit(resource.getName())) { >+ //check if should index resource >+ if(isResourceToIndex(resource.getType(), resource.getName())) { >+ >+ switch (delta.getKind()) { >+ case IResourceDelta.CHANGED : { >+ /* ignore any change that is not a CONTENT, REPLACED, TYPE, >+ * or MOVE_FROM change >+ */ >+ if( !((delta.getFlags() & IResourceDelta.CONTENT) != 0) && >+ !((delta.getFlags() & IResourceDelta.REPLACED) != 0) && >+ !((delta.getFlags() & IResourceDelta.TYPE) != 0) && >+ !(((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0))) { >+ >+ break; >+ } >+ } >+ //$FALL-THROUGH$ it is intended that sometimes a change will fall through to add >+ case IResourceDelta.ADDED : { >+ if((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) { >+ //create add move from action >+ this.fBatchedResourceEvents.put(resource, new ResourceEvent( >+ this.fSource, >+ AbstractIndexManager.ACTION_ADD_MOVE_FROM, >+ delta.getMovedFromPath())); >+ >+ } else { >+ //create add action >+ this.fBatchedResourceEvents.put(resource, new ResourceEvent( >+ this.fSource, >+ AbstractIndexManager.ACTION_ADD, >+ null)); >+ } >+ >+ break; >+ } >+ case IResourceDelta.REMOVED : { >+ if((delta.getFlags() & IResourceDelta.MOVED_TO) != 0) { >+ //create remove move to action >+ this.fBatchedResourceEvents.put(resource, new ResourceEvent( >+ this.fSource, >+ AbstractIndexManager.ACTION_REMOVE_MOVE_TO, >+ delta.getMovedToPath())); >+ } else { >+ //create remove action >+ this.fBatchedResourceEvents.put(resource, new ResourceEvent( >+ this.fSource, >+ AbstractIndexManager.ACTION_REMOVE, >+ null)); >+ } >+ break; >+ } >+ } >+ } >+ >+ visitChildren = true; >+ } else { >+ visitChildren = false; >+ } >+ >+ //deal with trying to report progress >+ if(visitChildren) { >+ this.fPredictedWorkRemaining += delta.getAffectedChildren().length; >+ } >+ this.fProgress.setWorkRemaining(this.fPredictedWorkRemaining); >+ this.fProgress.worked(1); >+ --this.fPredictedWorkRemaining; >+ >+ //batch up resource changes before sending them out >+ if(this.fBatchedResourceEvents.size() >= BATCH_UP_AMONT) { >+ this.processBatchedResourceEvents(); >+ } >+ >+ return visitChildren; >+ } >+ >+ /** >+ * <p>Sends any batched up resource events created by this visitor to the >+ * {@link ResourceEventProcessingJob}.<p> >+ * >+ * <p><b>NOTE:</b> This will be called every so often as the visitor is >+ * visiting resources but needs to be called a final time by the user of >+ * this visitor to be sure the final events are sent off</p> >+ */ >+ protected void processBatchedResourceEvents() { >+ AbstractIndexManager.this.fResourceEventProcessingJob.addResourceEvents( >+ this.fBatchedResourceEvents); >+ this.fBatchedResourceEvents.clear(); >+ } >+ } >+ >+ /** >+ * <p>Collects {@link ResourceEvent}s from the different sources and then processes >+ * each one by calling {@link AbstractIndexManager#performAction(byte, byte, IResource, IPath)} >+ * for each {@link ResourceEvent}.</p> >+ * >+ * @see AbstractIndexManager#performAction(byte, byte, IResource, IPath) >+ */ >+ private class ResourceEventProcessingJob extends Job { >+ /** Length to delay when scheduling job */ >+ private static final int DELAY = 500; >+ >+ /** >+ * <p>Name of the file where resource events still to index >+ * will be preserved for the next start up.</p> >+ */ >+ private static final String PRESERVED_RESOURCE_EVENTS_TO_PROCESS_FILE_NAME = ".preservedResourceEvents"; //$NON-NLS-1$ >+ >+ /** >+ * <p>This needs to be updated if {@link #preserveRecievedResourceEvents()} ever >+ * changes how it persists resource events so that {@link #loadPreservedRecievedResourceEvents(SubMonitor)} >+ * knows when opening a file that the format is of the current version and if not >+ * knows it does not know how to read the older version.</p> >+ * >+ * @see #preserveRecievedResourceEvents() >+ * @see #loadPreservedRecievedResourceEvents(SubMonitor) >+ */ >+ private static final long serialVersionUID = 1L; >+ >+ /** Whether this job has been paused or not */ >+ private volatile boolean fIsPaused; >+ >+ /** >+ * {@link Map}<{@link IResource}, {@link ResourceEvent}> >+ * <p>The list of resources events to be processed</p> >+ */ >+ private Map fResourceEvents; >+ >+ /** Lock used when accessing {@link #fBatchedResourceEvents} */ >+ private final Object fResourceEventsLock = new Object(); >+ >+ /** >+ * Locked used for allowing other jobs to wait on this job. This job >+ * will notify those waiting on this lock whenever it is done processing >+ * all resource events it currently knows about. >+ * >+ * @see #waitForConsistant(int) >+ */ >+ private final Object fToNotifyLock = new Object(); >+ >+ /** >+ * <p>Sets up this job as a long running system job</p> >+ */ >+ protected ResourceEventProcessingJob() { >+ super(AbstractIndexManager.this.fName + ": " + //$NON-NLS-1$ >+ SSECoreMessages.IndexManager_Processing_resource_events); >+ >+ //set this up as a long running system job >+ this.setUser(false); >+ this.setSystem(true); >+ this.setPriority(Job.LONG); >+ >+ this.fIsPaused = false; >+ this.fResourceEvents = new LinkedHashMap(); >+ } >+ >+ /** >+ * <p>Loads any preserved {@link ResourceEvent}s from the last time {@link #stop(boolean)} >+ * was invoked and schedules the job to be run</p> >+ * >+ * <p><b>NOTE: </b>Should be used instead of of calling {@link Job#schedule()} >+ * because this method also takes care of loading preserved state.</p> >+ * >+ * @param loadPreservedResourceEvents <code>true</code> if should load any >+ * preserved {@link ResourceEvent}s from the last time {@link #stop(boolean)} >+ * was invoked >+ * >+ * @return <code>true</code> if either <code>loadPreservedResourceEvents</code> >+ * was false or there was success in loading the preserved {@link ResourceEvent}s. >+ * If <code>false</code> then some {@link ResourceEvent}s may have been loosed >+ * and to insure index consistency with the workspace a full workspace re-index >+ * is needed. >+ * >+ * @see #stop(boolean) >+ */ >+ protected synchronized boolean start(boolean loadPreservedResourceEvents, >+ SubMonitor progress) { >+ >+ boolean successLoadingPreserved = true; >+ >+ //attempt to load preserved resource events if requested >+ if(!loadPreservedResourceEvents) { >+ File preservedResourceEventsFile = this.getPreservedResourceEventsFile(); >+ preservedResourceEventsFile.delete(); >+ } else { >+ successLoadingPreserved = this.loadPreservedRecievedResourceEvents(progress); >+ } >+ >+ //start up the job >+ this.schedule(); >+ >+ return successLoadingPreserved; >+ } >+ >+ /** >+ * <p>Immediately stops the job and preserves any {@link ResourceEvent}s in the queue >+ * to be processed by not yet processed if requested</p> >+ * >+ * @param preserveResourceEvents <code>true</code> to preserve any {@link ResourceEvent}s >+ * in the queue yet to be processed, <code>false</code> otherwise >+ * >+ * @return <code>true</code> if either <code>preserveResourceEvents</code> is >+ * <code>false</code> or if there was success in preserving the {@link ResourceEvent}s >+ * yet to be processed. If <code>false</code> then the preserving failed and a >+ * full workspace re-processing is needed the next time the manger is started >+ * >+ * @throws InterruptedException This could happen when trying to cancel or join >+ * the job in progress, but it really shouldn't >+ * >+ * @see #start(boolean, SubMonitor) >+ */ >+ protected synchronized boolean stop(boolean preserveResourceEvents) throws InterruptedException { >+ //this will not block indefinitely because it is known this job can be canceled >+ this.cancel(); >+ this.join(); >+ >+ //preserve if requested, else be sure no preserve file is left over for next start >+ boolean success = true; >+ if(preserveResourceEvents && this.hasResourceEventsToProcess()) { >+ success = this.preserveRecievedResourceEvents(); >+ } else { >+ this.getPreservedResourceEventsFile().delete(); >+ } >+ >+ return success; >+ } >+ >+ /** >+ * @return <code>true</code> if job is currently running or paused >+ * >+ * @see #pause() >+ * @see #unPause() >+ */ >+ protected synchronized boolean isProcessing() { >+ return this.getState() != Job.NONE || this.fIsPaused; >+ } >+ >+ /** >+ * <p>Un-pauses this job. This has no effect if the job is already running.</p> >+ * <p>This should be used in place of {@link Job#schedule()} to reset state >+ * caused by calling {@link #pause()}</p> >+ * >+ * @see #pause() >+ */ >+ protected synchronized void unPause() { >+ this.fIsPaused = false; >+ >+ //get the job running again depending on its current state >+ if(this.getState() == Job.SLEEPING) { >+ this.wakeUp(DELAY); >+ } else { >+ this.schedule(DELAY); >+ } >+ } >+ >+ /** >+ * <p>Pauses this job, even if it is running</p> >+ * <p>This should be used in place of {@link Job#sleep()} because {@link Job#sleep()} >+ * will not pause a job that is already running but calling this will pause this job >+ * even if it is running. {@link #unPause()} must be used to start this job again</p> >+ * >+ * @see #unPause() >+ */ >+ protected synchronized void pause() { >+ //if job is already running this will force it to pause >+ this.fIsPaused = true; >+ >+ //this only works if the job is not running >+ this.sleep(); >+ } >+ >+ /** >+ * <p>Adds a batch of {@link ResourceEvent}s to the queue of events to be processed. >+ * Will also un-pause the job if it is not already running</p> >+ * >+ * @param resourceEvents {@link Map}<{@link IResource}, {@link ResourceEvent}> >+ * A batch of {@link ResourceEvent}s to be processed >+ * >+ * @see #addResourceEvent(ResourceEvent) >+ * @see #unPause() >+ */ >+ protected void addResourceEvents(Map resourceEvents) { >+ Iterator iter = resourceEvents.keySet().iterator(); >+ while(iter.hasNext()) { >+ IResource resource = (IResource)iter.next(); >+ ResourceEvent resourceEvent = (ResourceEvent)resourceEvents.get(resource); >+ addResourceEvent(resource, resourceEvent); >+ } >+ >+ //un-pause the processor if it is not already running >+ if(!isProcessing()) { >+ this.unPause(); >+ } >+ } >+ >+ /** >+ * <p>Gets the number of {@link ResourceEvent}s left to process by this job. This >+ * count is only valid for the exact moment it is returned because events are >+ * constantly being added and removed from the queue of events to process</p> >+ * >+ * @return the number of {@link ResourceEvent}s left to process >+ */ >+ protected int getNumResourceEventsToProcess() { >+ return this.fResourceEvents.size(); >+ } >+ >+ /** >+ * <p>Blocks until either the given timeout elapses (0 means never to timeout), or >+ * there are currently no {@link ResourceEvent}s to process or being processed >+ * by this job</p> >+ * >+ * @param timeout block until either this timeout elapses (0 means never to timeout) >+ * or there are currently no {@link ResourceEvent}s to process or being processed >+ * by this job >+ * >+ * @throws InterruptedException This can happen when waiting for a lock >+ */ >+ protected void waitForConsistant(int timeout) throws InterruptedException { >+ if(hasResourceEventsToProcess() || isProcessing()) { >+ synchronized (this.fToNotifyLock) { >+ this.fToNotifyLock.wait(timeout); >+ } >+ } >+ } >+ >+ /** >+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) >+ */ >+ protected IStatus run(IProgressMonitor monitor) { >+ try { >+ //report status >+ SubMonitor progress = SubMonitor.convert(monitor); >+ >+ while(!this.fIsPaused && !monitor.isCanceled() && this.hasResourceEventsToProcess()) { >+ //report status >+ progress.setTaskName(AbstractIndexManager.this.fName + ": " + //$NON-NLS-1$ >+ NLS.bind(SSECoreMessages.IndexManager_Indexing_0_Files, >+ "" + getNumResourceEventsToProcess())); //$NON-NLS-1$ >+ progress.setWorkRemaining(getNumResourceEventsToProcess()); >+ >+ //get the next event to process >+ ResourceEvent resourceEvent = null; >+ IResource resource = null; >+ synchronized (this.fResourceEventsLock) { >+ resource = (IResource) this.fResourceEvents.keySet().iterator().next(); >+ resourceEvent = (ResourceEvent)this.fResourceEvents.remove(resource); >+ } >+ >+ //report status >+ monitor.subTask(resource.getName()); >+ >+ //perform action safely >+ final byte source = resourceEvent.fSource; >+ final byte action = resourceEvent.fAction; >+ final IResource finResource = resource; >+ final IPath movePath = resourceEvent.fMovePath; >+ SafeRunner.run(new ISafeRunnable() { >+ public void run() throws Exception { >+ AbstractIndexManager.this.performAction(source, action, >+ finResource, movePath); >+ } >+ >+ public void handleException(Throwable e) { >+ Logger.logException("Error while performing an update to the index. " + //$NON-NLS-1$ >+ AbstractIndexManager.LOG_ERROR_INDEX_INVALID, e); >+ } >+ }); >+ >+ //report progress >+ progress.worked(1); >+ >+ //avoid dead locks >+ Job.getJobManager().currentJob().yieldRule(monitor); >+ } >+ >+ //done work >+ monitor.done(); >+ } finally { >+ //want to be sure we notify no matter how we exit >+ this.notifyIfConsistant(); >+ } >+ >+ /* if canceled then return CANCEL, >+ * else if done or paused return OK >+ */ >+ IStatus exitStatus; >+ if(monitor.isCanceled()) { >+ exitStatus = Status.CANCEL_STATUS; >+ } else { >+ exitStatus = Status.OK_STATUS; >+ } >+ >+ return exitStatus; >+ } >+ >+ /** >+ * <p>If resource not already scheduled to be processed, schedule it >+ * else if resource already scheduled to be processed, update the action only if >+ * the new action comes from a resource change event.</p> >+ * >+ * <p>Ignore other sources for updating existing resource events because all other >+ * sources are "start-up" type sources and thus only {@link ResourceEvent} with a >+ * source of a resource change event trump existing events.</p> >+ * >+ * @param resourceEvent {@link ResourceEvent} to be processed by this job >+ */ >+ private void addResourceEvent(IResource resource, ResourceEvent resourceEvent) { >+ >+ synchronized (this.fResourceEventsLock) { >+ /* if resource not already scheduled to be processed, schedule it >+ * else if resource already scheduled to be processed, update the action only if >+ * the new action comes from a resource change event >+ */ >+ if(!this.fResourceEvents.containsKey(resource)) { >+ this.fResourceEvents.put(resource, resourceEvent); >+ } else if(resourceEvent.fSource == AbstractIndexManager.SOURCE_RESROUCE_CHANGE) { >+ ((ResourceEvent)this.fResourceEvents.get(resource)).fAction = resourceEvent.fAction; >+ } else { >+ //Purposely ignoring all other resource events >+ } >+ } >+ } >+ >+ /** >+ * @return <code>true</code> if there are any resources to process, >+ * <code>false</code> otherwise >+ */ >+ private boolean hasResourceEventsToProcess() { >+ return !this.fResourceEvents.isEmpty(); >+ } >+ >+ /** >+ * <p>Preserves all of the resource events that have been received by this >+ * manager but not yet processed</p> >+ * >+ * <p>If this operation was successful then the next time the manager starts >+ * it can load these events and process them. If it was not successful then a >+ * full re-processing of the entire workspace will need to take place to be >+ * sure the index is consistent.</p> >+ * >+ * <p><b>NOTE:</b> If this method changes how it preserves these events then >+ * {@link #serialVersionUID} will need to be incremented so that the manger >+ * does not attempt to load an old version of the file that may exist in a users >+ * workspace. Also {@link #loadPreservedRecievedResourceEvents(SubMonitor)} will >+ * have to be updated to load the new file structure</p> >+ * >+ * @return <code>true</code> if successfully preserved the resources the resource >+ * events that have been received by not yet processed, <code>false</code> otherwise >+ * >+ * @see #serialVersionUID >+ * @see #loadPreservedRecievedResourceEvents(SubMonitor) >+ */ >+ private boolean preserveRecievedResourceEvents() { >+ File preservedResourceEventsFile = this.getPreservedResourceEventsFile(); >+ boolean success = true; >+ >+ synchronized (this.fResourceEventsLock) { >+ DataOutputStream dos = null; >+ try { >+ //if file already exists delete it >+ if(preservedResourceEventsFile.exists()) { >+ preservedResourceEventsFile.delete(); >+ preservedResourceEventsFile.createNewFile(); >+ } >+ >+ //create output objects >+ FileOutputStream fos = new FileOutputStream(preservedResourceEventsFile); >+ BufferedOutputStream bos = new BufferedOutputStream(fos); >+ dos = new DataOutputStream(bos); >+ >+ //write serial version >+ dos.writeLong(serialVersionUID); >+ >+ //write size >+ dos.writeInt(this.getNumResourceEventsToProcess()); >+ >+ //write out all the information needed to restore the resource events to process >+ Iterator iter = this.fResourceEvents.keySet().iterator(); >+ while(iter.hasNext()) { >+ IResource resource = (IResource)iter.next(); >+ ResourceEvent resourceEvent = (ResourceEvent)this.fResourceEvents.get(resource); >+ >+ if(resourceEvent.fSource != AbstractIndexManager.SOURCE_WORKSPACE_SCAN) { >+ //write out information >+ dos.writeByte(resourceEvent.fAction); >+ dos.writeByte(resource.getType()); >+ dos.writeBytes(resource.getLocation().toPortableString()); >+ dos.writeByte('\0'); >+ if(resourceEvent.fMovePath != null) { >+ dos.writeBytes(resourceEvent.fMovePath.toPortableString()); >+ } >+ dos.writeByte('\0'); >+ } >+ } >+ >+ this.fResourceEvents.clear(); >+ >+ dos.flush(); >+ } catch (FileNotFoundException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Exception while opening file to preserve resrouces to index.", //$NON-NLS-1$ >+ e); >+ success = false; >+ } catch (IOException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Exception while writing to file to preserve resrouces to index.", //$NON-NLS-1$ >+ e); >+ success = false; >+ } finally { >+ //be sure to close output >+ if(dos != null) { >+ try { >+ dos.close(); >+ } catch (IOException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Exception while closing file with preserved resources to index.", //$NON-NLS-1$ >+ e); >+ success = false; >+ } >+ } >+ } >+ >+ //if failed, for consistency must do a full re-process next workspace load >+ if(!success) { >+ preservedResourceEventsFile.delete(); >+ } >+ } >+ >+ return success; >+ } >+ >+ /** >+ * <p>Loads the received resource events that were preserved during the manger's >+ * last shut down so they can be processed now</p> >+ * >+ * <p>If this operation is not successful then a full re-processing of the >+ * entire workspace is needed to be sure the index is consistent.</p> >+ * >+ * @param progress used to report status of loading the preserved received resource events >+ * @return <code>true</code> if the loading of the preserved received resource events >+ * was successful, <code>false</code> otherwise. >+ * >+ * @see #serialVersionUID >+ * @see #preserveRecievedResourceEvents() >+ */ >+ private boolean loadPreservedRecievedResourceEvents(SubMonitor progress) { >+ progress.subTask(SSECoreMessages.IndexManager_processing_deferred_resource_changes); >+ >+ boolean success = true; >+ File preservedResourceEventsFile = this.getPreservedResourceEventsFile(); >+ >+ if(preservedResourceEventsFile.exists()) { >+ Map preservedResrouceEvents = null; >+ >+ DataInputStream dis = null; >+ try { >+ FileInputStream fis = new FileInputStream(preservedResourceEventsFile); >+ BufferedInputStream bis = new BufferedInputStream(fis); >+ dis = new DataInputStream(bis); >+ >+ //check serial version first >+ long preservedSerialVersionUID = dis.readLong(); >+ if(preservedSerialVersionUID == serialVersionUID) { >+ >+ //read each record >+ int numberOfRecords = dis.readInt(); >+ preservedResrouceEvents = new LinkedHashMap(numberOfRecords); >+ progress.setWorkRemaining(numberOfRecords); >+ for(int i = 0; i < numberOfRecords; ++i) { >+ //action is first byte >+ byte action = dis.readByte(); >+ >+ //file type is the next byte >+ byte fileType = dis.readByte(); >+ >+ //resource location are the next bytes >+ StringBuffer resourceLocationBuffer = new StringBuffer(); >+ byte b = dis.readByte(); >+ while(b != '\0') { >+ resourceLocationBuffer.append(b); >+ } >+ >+ //move path are the next bytes >+ StringBuffer movePathBuffer = new StringBuffer(); >+ b = dis.readByte(); >+ while(b != '\0') { >+ movePathBuffer.append(b); >+ } >+ >+ //get the resource >+ IResource resource = null; >+ IPath resourcePath = new Path(resourceLocationBuffer.toString()); >+ if(fileType == IResource.FILE) { >+ resource = >+ ResourcesPlugin.getWorkspace().getRoot().getFile(resourcePath); >+ } else { >+ resource = >+ ResourcesPlugin.getWorkspace().getRoot().getFolder(resourcePath); >+ } >+ >+ //get the move path >+ IPath movePath = null; >+ if(movePathBuffer.length() != 0) { >+ movePath = new Path(movePathBuffer.toString()); >+ } >+ >+ //add the object to the list of of preserved resources >+ preservedResrouceEvents.put(resource, new ResourceEvent( >+ AbstractIndexManager.SOURCE_PRESERVED_RESOURCES_TO_INDEX, >+ action, movePath)); >+ >+ progress.worked(1); >+ } >+ } else { >+ success = false; >+ } >+ } catch (FileNotFoundException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Exception while opening file to read preserved resrouces to index.", //$NON-NLS-1$ >+ e); >+ success = false; >+ } catch (IOException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Exception while reading from file of preserved resrouces to index.", //$NON-NLS-1$ >+ e); >+ success = false; >+ } finally { >+ if(dis != null) { >+ try { >+ dis.close(); >+ } catch (IOException e) { >+ Logger.logException(AbstractIndexManager.this.fName + >+ ": Exception while closing file of preserved resources" + //$NON-NLS-1$ >+ " to index that was just read. This should have no" + //$NON-NLS-1$ >+ " effect on the consistency of the index.", //$NON-NLS-1$ >+ e); >+ } >+ } >+ } >+ >+ //if success loading preserved then add to master list >+ if(success) { >+ synchronized (this.fResourceEventsLock) { >+ Iterator iter = preservedResrouceEvents.keySet().iterator(); >+ while(iter.hasNext()) { >+ IResource resource = (IResource)iter.next(); >+ ResourceEvent event = (ResourceEvent)preservedResrouceEvents.get(resource); >+ this.fResourceEvents.put(resource, event); >+ } >+ } >+ } else { >+ //failed reading file, so delete it >+ preservedResourceEventsFile.delete(); >+ } >+ } >+ >+ return success; >+ } >+ >+ /** >+ * @return {@link File} that contains any resource events received but not processed >+ * by this manager the last time it shutdown. This file may or may not actually >+ * exist. >+ * >+ * @see #preserveRecievedResourceEvents() >+ * @see #loadPreservedRecievedResourceEvents(SubMonitor) >+ */ >+ private File getPreservedResourceEventsFile() { >+ IPath preservedResroucesToIndexPath = >+ AbstractIndexManager.this.getWorkingLocation().append( >+ PRESERVED_RESOURCE_EVENTS_TO_PROCESS_FILE_NAME); >+ return new File(preservedResroucesToIndexPath.toOSString()); >+ } >+ >+ /** >+ * <p>If all resource events have been processed >+ */ >+ private void notifyIfConsistant() { >+ if(!this.hasResourceEventsToProcess()) { >+ synchronized (this.fToNotifyLock) { >+ this.fToNotifyLock.notifyAll(); >+ } >+ } >+ } >+ } >+ >+ /** >+ * <p>Represents a resource that was discovered by this manager. Contains >+ * all the information this manager and the index needs to know about this >+ * resource. Such has how the manager was notified about this resource and >+ * the type of action occurring on the resource.</p> >+ */ >+ private static class ResourceEvent { >+ /** >+ * <p>The source of this resource event</p> >+ * >+ * @see AbstractIndexManager#SOURCE_RESROUCE_CHANGE >+ * @see AbstractIndexManager#SOURCE_SAVED_STATE >+ * @see AbstractIndexManager#SOURCE_WORKSPACE_SCAN >+ * @see AbstractIndexManager#SOURCE_PRESERVED_RESOURCES_TO_INDEX >+ */ >+ protected byte fSource; >+ >+ /** >+ * <p>The action that the index should take with this resource</p> >+ * >+ * @see AbstractIndexManager#ACTION_ADD >+ * @see AbstractIndexManager#ACTION_REMOVE >+ * @see AbstractIndexManager#ACTION_ADD_MOVE_FROM >+ * @see AbstractIndexManager#ACTION_REMOVE_MOVE_TO >+ */ >+ protected byte fAction; >+ >+ /** >+ * >+ * <p>If the {@link #fAction} is {@link AbstractIndexManager#ACTION_ADD_MOVE_FROM} or >+ * {@link AbstractIndexManager#ACTION_REMOVE_MOVE_TO} then this field will have the >+ * path the resource was moved from or moved to. Else this field will be <code>null</code></p> >+ * >+ * <p><b>NOTE: </b>Maybe <code>null</code>.</p> >+ * >+ * @see AbstractIndexManager#ACTION_ADD_MOVE_FROM >+ * @see AbstractIndexManager#ACTION_REMOVE_MOVE_TO >+ */ >+ protected IPath fMovePath; >+ >+ /** >+ * <p>Creates a resource event that the index needs to react to in some way</p> >+ * >+ * @param source source that the manger used to learn of this resource >+ * @param action action the index should take on this resource >+ * @param resource resource that the index should know about >+ * @param movePath if action is {@link AbstractIndexManager#ACTION_ADD_MOVE_FROM} or >+ * {@link AbstractIndexManager#ACTION_REMOVE_MOVE_TO} then this should be the path the >+ * resource was moved from or moved to respectively, else should be <code>null</code> >+ * >+ * @see AbstractIndexManager#SOURCE_RESROUCE_CHANGE >+ * @see AbstractIndexManager#SOURCE_SAVED_STATE >+ * @see AbstractIndexManager#SOURCE_WORKSPACE_SCAN >+ * @see AbstractIndexManager#SOURCE_PRESERVED_RESOURCES_TO_INDEX >+ * >+ * @see AbstractIndexManager#ACTION_ADD >+ * @see AbstractIndexManager#ACTION_REMOVE >+ * @see AbstractIndexManager#ACTION_ADD_MOVE_FROM >+ * @see AbstractIndexManager#ACTION_REMOVE_MOVE_TO >+ */ >+ protected ResourceEvent(byte source, byte action, IPath movePath) { >+ this.fSource = source; >+ this.fAction = action; >+ this.fMovePath = movePath; >+ } >+ } >+} >\ No newline at end of file >Index: src/org/eclipse/wst/sse/core/internal/SSECoreMessages.java >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/SSECoreMessages.java,v >retrieving revision 1.4 >diff -u -r1.4 SSECoreMessages.java >--- src/org/eclipse/wst/sse/core/internal/SSECoreMessages.java 24 Jun 2005 20:13:21 -0000 1.4 >+++ src/org/eclipse/wst/sse/core/internal/SSECoreMessages.java 1 Sep 2010 12:23:11 -0000 >@@ -1,5 +1,5 @@ > /********************************************************************** >- * Copyright (c) 2005 IBM Corporation and others. All rights reserved. This >+ * Copyright (c) 2005, 2010 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 >@@ -36,4 +36,13 @@ > public static String TaskScanningJob_0; > public static String TaskScanningJob_1; > public static String Migrate_Charset; >+ >+ public static String IndexManager_starting; >+ public static String IndexManager_Indexing_0_Files; >+ public static String IndexManager_processing_deferred_resource_changes; >+ public static String IndexManager_Processing_entire_workspace_for_the_first_time; >+ public static String IndexManager_processing_recent_resource_changes; >+ public static String IndexManager_0_resources_to_go; >+ public static String IndexManager_Waiting_for_0; >+ public static String IndexManager_Processing_resource_events; > } >Index: src/org/eclipse/wst/sse/core/internal/SSECorePluginResources.properties >=================================================================== >RCS file: /cvsroot/webtools/sourceediting/plugins/org.eclipse.wst.sse.core/src/org/eclipse/wst/sse/core/internal/SSECorePluginResources.properties,v >retrieving revision 1.5 >diff -u -r1.5 SSECorePluginResources.properties >--- src/org/eclipse/wst/sse/core/internal/SSECorePluginResources.properties 10 Apr 2007 20:07:25 -0000 1.5 >+++ src/org/eclipse/wst/sse/core/internal/SSECorePluginResources.properties 1 Sep 2010 12:23:11 -0000 >@@ -1,5 +1,5 @@ > ############################################################################### >-# Copyright (c) 2001, 2005 IBM Corporation and others. >+# Copyright (c) 2001, 2010 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,12 @@ > TaskScanningJob_1=Errors while detecting Tasks > ############################################################################### > Migrate_Charset=Migrate Charset >+ >+IndexManager_starting=Starting >+IndexManager_Indexing_0_Files=Indexing {0} Files >+IndexManager_processing_deferred_resource_changes=Processing deferred resource changes >+IndexManager_Processing_entire_workspace_for_the_first_time=Processing entire workspace for the first time >+IndexManager_processing_recent_resource_changes=Processing recent resource changes >+IndexManager_0_resources_to_go={0} resources to go >+IndexManager_Waiting_for_0=Waiting for {0} >+IndexManager_Processing_resource_events=Processing Resource Events >\ No newline at end of file
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 323392
:
177432
| 177941 |
177942