eacba5824366f52d909dcf9b1b3dfdf33e442a77
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / DeltaProcessor.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.io.File;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.Map;
20
21 import net.sourceforge.phpdt.core.ElementChangedEvent;
22 import net.sourceforge.phpdt.core.IClasspathEntry;
23 import net.sourceforge.phpdt.core.IElementChangedListener;
24 import net.sourceforge.phpdt.core.IJavaElement;
25 import net.sourceforge.phpdt.core.IJavaElementDelta;
26 import net.sourceforge.phpdt.core.IJavaModel;
27 import net.sourceforge.phpdt.core.IJavaProject;
28 import net.sourceforge.phpdt.core.JavaCore;
29 import net.sourceforge.phpdt.core.JavaModelException;
30 import net.sourceforge.phpdt.internal.core.builder.PHPBuilder;
31 import net.sourceforge.phpdt.internal.core.util.Util;
32 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
33 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
34
35 import org.eclipse.core.resources.IFile;
36 import org.eclipse.core.resources.IProject;
37 import org.eclipse.core.resources.IResource;
38 import org.eclipse.core.resources.IResourceChangeEvent;
39 import org.eclipse.core.resources.IResourceChangeListener;
40 import org.eclipse.core.resources.IResourceDelta;
41 import org.eclipse.core.resources.IResourceDeltaVisitor;
42 import org.eclipse.core.resources.IWorkspace;
43 import org.eclipse.core.resources.ResourcesPlugin;
44 import org.eclipse.core.runtime.CoreException;
45 import org.eclipse.core.runtime.IPath;
46 import org.eclipse.core.runtime.ISafeRunnable;
47 import org.eclipse.core.runtime.Platform;
48 import org.eclipse.core.runtime.QualifiedName;
49
50 /**
51  * This class is used by <code>JavaModelManager</code> to convert
52  * <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s. It
53  * also does some processing on the <code>JavaElement</code>s involved (e.g.
54  * closing them or updating classpaths).
55  */
56 public class DeltaProcessor implements IResourceChangeListener {
57
58         final static int IGNORE = 0;
59
60         final static int SOURCE = 1;
61
62         final static int BINARY = 2;
63
64         final static String EXTERNAL_JAR_ADDED = "external jar added"; //$NON-NLS-1$
65
66         final static String EXTERNAL_JAR_REMOVED = "external jar removed"; //$NON-NLS-1$
67
68         final static String EXTERNAL_JAR_CHANGED = "external jar changed"; //$NON-NLS-1$
69
70         final static String EXTERNAL_JAR_UNCHANGED = "external jar unchanged"; //$NON-NLS-1$
71
72         final static String INTERNAL_JAR_IGNORE = "internal jar ignore"; //$NON-NLS-1$
73
74         private final static int NON_JAVA_RESOURCE = -1;
75
76         public static boolean DEBUG = false;
77
78         public static boolean VERBOSE = false;
79
80         public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with
81                                                                                                                 // ElementChangedEvent
82                                                                                                                 // event masks
83
84         /**
85          * The <code>JavaElementDelta</code> corresponding to the
86          * <code>IResourceDelta</code> being translated.
87          */
88         protected JavaElementDelta currentDelta;
89
90         // protected IndexManager indexManager = new IndexManager();
91
92         /* A table from IPath (from a classpath entry) to RootInfo */
93         public Map roots;
94
95         /*
96          * A table from IPath (from a classpath entry) to ArrayList of RootInfo Used
97          * when an IPath corresponds to more than one root
98          */
99         Map otherRoots;
100
101         /* Whether the roots tables should be recomputed */
102         public boolean rootsAreStale = true;
103
104         /*
105          * A table from IPath (from a classpath entry) to RootInfo from the last
106          * time the delta processor was invoked.
107          */
108         public Map oldRoots;
109
110         /*
111          * A table from IPath (from a classpath entry) to ArrayList of RootInfo from
112          * the last time the delta processor was invoked. Used when an IPath
113          * corresponds to more than one root
114          */
115         Map oldOtherRoots;
116
117         /*
118          * A table from IPath (a source attachment path from a classpath entry) to
119          * IPath (a root path)
120          */
121         Map sourceAttachments;
122
123         /*
124          * The java element that was last created (see createElement(IResource)).
125          * This is used as a stack of java elements (using getParent() to pop it,
126          * and using the various get*(...) to push it.
127          */
128         Openable currentElement;
129
130         /*
131          * Queue of deltas created explicily by the Java Model that have yet to be
132          * fired.
133          */
134         public ArrayList javaModelDeltas = new ArrayList();
135
136         /*
137          * Queue of reconcile deltas on working copies that have yet to be fired.
138          * This is a table form IWorkingCopy to IJavaElementDelta
139          */
140         public HashMap reconcileDeltas = new HashMap();
141
142         /*
143          * Turns delta firing on/off. By default it is on.
144          */
145         private boolean isFiring = true;
146
147         public HashMap externalTimeStamps = new HashMap();
148
149         public HashSet projectsToUpdate = new HashSet();
150
151         // list of root projects which namelookup caches need to be updated for
152         // dependents
153         // TODO: (jerome) is it needed? projectsToUpdate might be sufficient
154         public HashSet projectsForDependentNamelookupRefresh = new HashSet();
155
156         /*
157          * The global state of delta processing.
158          */
159         private DeltaProcessingState state;
160
161         /*
162          * The Java model manager
163          */
164         private JavaModelManager manager;
165
166         /*
167          * A table from IJavaProject to an array of IPackageFragmentRoot. This table
168          * contains the pkg fragment roots of the project that are being deleted.
169          */
170         Map removedRoots;
171
172         /*
173          * A list of IJavaElement used as a scope for external archives refresh
174          * during POST_CHANGE. This is null if no refresh is needed.
175          */
176         HashSet refreshedElements;
177
178         class OutputsInfo {
179                 IPath[] paths;
180
181                 int[] traverseModes;
182
183                 int outputCount;
184
185                 OutputsInfo(IPath[] paths, int[] traverseModes, int outputCount) {
186                         this.paths = paths;
187                         this.traverseModes = traverseModes;
188                         this.outputCount = outputCount;
189                 }
190
191                 public String toString() {
192                         if (this.paths == null)
193                                 return "<none>"; //$NON-NLS-1$
194                         StringBuffer buffer = new StringBuffer();
195                         for (int i = 0; i < this.outputCount; i++) {
196                                 buffer.append("path="); //$NON-NLS-1$
197                                 buffer.append(this.paths[i].toString());
198                                 buffer.append("\n->traverse="); //$NON-NLS-1$
199                                 switch (this.traverseModes[i]) {
200                                 case BINARY:
201                                         buffer.append("BINARY"); //$NON-NLS-1$
202                                         break;
203                                 case IGNORE:
204                                         buffer.append("IGNORE"); //$NON-NLS-1$
205                                         break;
206                                 case SOURCE:
207                                         buffer.append("SOURCE"); //$NON-NLS-1$
208                                         break;
209                                 default:
210                                         buffer.append("<unknown>"); //$NON-NLS-1$
211                                 }
212                                 if (i + 1 < this.outputCount) {
213                                         buffer.append('\n');
214                                 }
215                         }
216                         return buffer.toString();
217                 }
218         }
219
220         class RootInfo {
221                 IJavaProject project;
222
223                 IPath rootPath;
224
225                 char[][] exclusionPatterns;
226
227                 RootInfo(IJavaProject project, IPath rootPath,
228                                 char[][] exclusionPatterns) {
229                         this.project = project;
230                         this.rootPath = rootPath;
231                         this.exclusionPatterns = exclusionPatterns;
232                 }
233
234                 boolean isRootOfProject(IPath path) {
235                         return this.rootPath.equals(path)
236                                         && this.project.getProject().getFullPath().isPrefixOf(path);
237                 }
238
239                 public String toString() {
240                         StringBuffer buffer = new StringBuffer("project="); //$NON-NLS-1$
241                         if (this.project == null) {
242                                 buffer.append("null"); //$NON-NLS-1$
243                         } else {
244                                 buffer.append(this.project.getElementName());
245                         }
246                         buffer.append("\npath="); //$NON-NLS-1$
247                         if (this.rootPath == null) {
248                                 buffer.append("null"); //$NON-NLS-1$
249                         } else {
250                                 buffer.append(this.rootPath.toString());
251                         }
252                         buffer.append("\nexcluding="); //$NON-NLS-1$
253                         if (this.exclusionPatterns == null) {
254                                 buffer.append("null"); //$NON-NLS-1$
255                         } else {
256                                 for (int i = 0, length = this.exclusionPatterns.length; i < length; i++) {
257                                         buffer.append(new String(this.exclusionPatterns[i]));
258                                         if (i < length - 1) {
259                                                 buffer.append("|"); //$NON-NLS-1$
260                                         }
261                                 }
262                         }
263                         return buffer.toString();
264                 }
265         }
266
267         // DeltaProcessor(JavaModelManager manager) {
268         // this.manager = manager;
269         // }
270
271         /*
272          * Type of event that should be processed no matter what the real event type
273          * is.
274          */
275         public int overridenEventType = -1;
276
277         public DeltaProcessor(DeltaProcessingState state, JavaModelManager manager) {
278                 this.state = state;
279                 this.manager = manager;
280         }
281
282         /*
283          * Adds the dependents of the given project to the list of the projects to
284          * update.
285          */
286         // void addDependentProjects(IPath projectPath, HashSet result) {
287         // try {
288         // IJavaProject[] projects = this.manager.getJavaModel().getJavaProjects();
289         // for (int i = 0, length = projects.length; i < length; i++) {
290         // IJavaProject project = projects[i];
291         // IClasspathEntry[] classpath =
292         // ((JavaProject)project).getExpandedClasspath(true);
293         // for (int j = 0, length2 = classpath.length; j < length2; j++) {
294         // IClasspathEntry entry = classpath[j];
295         // if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT
296         // && entry.getPath().equals(projectPath)) {
297         // result.add(project);
298         // }
299         // }
300         // }
301         // } catch (JavaModelException e) {
302         // }
303         // }
304         /*
305          * Adds the given element to the list of elements used as a scope for
306          * external jars refresh.
307          */
308         public void addForRefresh(IJavaElement element) {
309                 if (this.refreshedElements == null) {
310                         this.refreshedElements = new HashSet();
311                 }
312                 this.refreshedElements.add(element);
313         }
314
315         /*
316          * Adds the given project and its dependents to the list of the projects to
317          * update.
318          */
319         void addToProjectsToUpdateWithDependents(IProject project) {
320                 this.projectsToUpdate.add(JavaCore.create(project));
321                 // this.addDependentProjects(project.getFullPath(),
322                 // this.projectsToUpdate);
323         }
324
325         /**
326          * Adds the given child handle to its parent's cache of children.
327          */
328         protected void addToParentInfo(Openable child) {
329
330                 Openable parent = (Openable) child.getParent();
331                 if (parent != null && parent.isOpen()) {
332                         try {
333                                 JavaElementInfo info = (JavaElementInfo) parent
334                                                 .getElementInfo();
335                                 info.addChild(child);
336                         } catch (JavaModelException e) {
337                                 // do nothing - we already checked if open
338                         }
339                 }
340         }
341
342         /**
343          * Check all external archive (referenced by given roots, projects or model)
344          * status and issue a corresponding root delta. Also triggers index updates
345          */
346         // public void checkExternalArchiveChanges(IJavaElement[] refreshedElements,
347         // IProgressMonitor monitor) throws JavaModelException {
348         // try {
349         // for (int i = 0, length = refreshedElements.length; i < length; i++) {
350         // this.addForRefresh(refreshedElements[i]);
351         // }
352         // boolean hasDelta = this.createExternalArchiveDelta(monitor);
353         // if (monitor != null && monitor.isCanceled()) return;
354         // if (hasDelta){
355         // // force classpath marker refresh of affected projects
356         // JavaModel.flushExternalFileCache();
357         // IJavaElementDelta[] projectDeltas =
358         // this.currentDelta.getAffectedChildren();
359         // for (int i = 0, length = projectDeltas.length; i < length; i++) {
360         // IJavaElementDelta delta = projectDeltas[i];
361         // ((JavaProject)delta.getElement()).getResolvedClasspath(
362         // true, // ignoreUnresolvedEntry
363         // true); // generateMarkerOnError
364         // }
365         // if (this.currentDelta != null) { // if delta has not been fired while
366         // creating markers
367         // this.manager.fire(this.currentDelta,
368         // JavaModelManager.DEFAULT_CHANGE_EVENT);
369         // }
370         // }
371         // } finally {
372         // this.currentDelta = null;
373         // if (monitor != null) monitor.done();
374         // }
375         // }
376         /*
377          * Check if external archives have changed and create the corresponding
378          * deltas. Returns whether at least on delta was created.
379          */
380         // public boolean createExternalArchiveDelta(IProgressMonitor monitor)
381         // throws JavaModelException {
382         //              
383         // if (this.refreshedElements == null) return false;
384         //                      
385         // HashMap externalArchivesStatus = new HashMap();
386         // boolean hasDelta = false;
387         //              
388         // // find JARs to refresh
389         // HashSet archivePathsToRefresh = new HashSet();
390         // try {
391         // Iterator iterator = this.refreshedElements.iterator();
392         // while (iterator.hasNext()) {
393         // IJavaElement element = (IJavaElement)iterator.next();
394         // switch(element.getElementType()){
395         // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
396         // archivePathsToRefresh.add(element.getPath());
397         // break;
398         // case IJavaElement.JAVA_PROJECT :
399         // IJavaProject project = (IJavaProject) element;
400         // if (!JavaProject.hasJavaNature(project.getProject())) {
401         // // project is not accessible or has lost its Java nature
402         // break;
403         // }
404         // IClasspathEntry[] classpath = project.getResolvedClasspath(true);
405         // for (int j = 0, cpLength = classpath.length; j < cpLength; j++){
406         // if (classpath[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
407         // archivePathsToRefresh.add(classpath[j].getPath());
408         // }
409         // }
410         // break;
411         // case IJavaElement.JAVA_MODEL :
412         // IJavaProject[] projects =
413         // manager.getJavaModel().getOldJavaProjectsList();
414         // for (int j = 0, projectsLength = projects.length; j < projectsLength;
415         // j++){
416         // project = projects[j];
417         // if (!JavaProject.hasJavaNature(project.getProject())) {
418         // // project is not accessible or has lost its Java nature
419         // continue;
420         // }
421         // classpath = project.getResolvedClasspath(true);
422         // for (int k = 0, cpLength = classpath.length; k < cpLength; k++){
423         // if (classpath[k].getEntryKind() == IClasspathEntry.CPE_LIBRARY){
424         // archivePathsToRefresh.add(classpath[k].getPath());
425         // }
426         // }
427         // }
428         // break;
429         // }
430         // }
431         // } finally {
432         // this.refreshedElements = null;
433         // }
434         //              
435         // // perform refresh
436         // IJavaProject[] projects =
437         // manager.getJavaModel().getOldJavaProjectsList();
438         // IWorkspaceRoot wksRoot = ResourcesPlugin.getWorkspace().getRoot();
439         // for (int i = 0, length = projects.length; i < length; i++) {
440         //                      
441         // if (monitor != null && monitor.isCanceled()) break;
442         //                      
443         // IJavaProject project = projects[i];
444         // if (!JavaProject.hasJavaNature(project.getProject())) {
445         // // project is not accessible or has lost its Java nature
446         // continue;
447         // }
448         // IClasspathEntry[] entries = project.getResolvedClasspath(true);
449         // for (int j = 0; j < entries.length; j++){
450         // if (entries[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
451         //                                      
452         // IPath entryPath = entries[j].getPath();
453         //                                      
454         // if (!archivePathsToRefresh.contains(entryPath)) continue; // not supposed
455         // to be refreshed
456         //                                      
457         // String status = (String)externalArchivesStatus.get(entryPath);
458         // if (status == null){
459         //                                              
460         // // compute shared status
461         // Object targetLibrary = JavaModel.getTarget(wksRoot, entryPath, true);
462         //              
463         // if (targetLibrary == null){ // missing JAR
464         // if (this.externalTimeStamps.containsKey(entryPath)){
465         // this.externalTimeStamps.remove(entryPath);
466         // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_REMOVED);
467         // // the jar was physically removed: remove the index
468         // indexManager.removeIndex(entryPath);
469         // }
470         //              
471         // } else if (targetLibrary instanceof File){ // external JAR
472         //              
473         // File externalFile = (File)targetLibrary;
474         //                                                      
475         // // check timestamp to figure if JAR has changed in some way
476         // Long oldTimestamp =(Long) this.externalTimeStamps.get(entryPath);
477         // long newTimeStamp = getTimeStamp(externalFile);
478         // if (oldTimestamp != null){
479         //              
480         // if (newTimeStamp == 0){ // file doesn't exist
481         // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_REMOVED);
482         // this.externalTimeStamps.remove(entryPath);
483         // // remove the index
484         // indexManager.removeIndex(entryPath);
485         //              
486         // } else if (oldTimestamp.longValue() != newTimeStamp){
487         // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_CHANGED);
488         // this.externalTimeStamps.put(entryPath, new Long(newTimeStamp));
489         // // first remove the index so that it is forced to be re-indexed
490         // indexManager.removeIndex(entryPath);
491         // // then index the jar
492         // indexManager.indexLibrary(entryPath, project.getProject());
493         // } else {
494         // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED);
495         // }
496         // } else {
497         // if (newTimeStamp == 0){ // jar still doesn't exist
498         // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_UNCHANGED);
499         // } else {
500         // externalArchivesStatus.put(entryPath, EXTERNAL_JAR_ADDED);
501         // this.externalTimeStamps.put(entryPath, new Long(newTimeStamp));
502         // // index the new jar
503         // indexManager.indexLibrary(entryPath, project.getProject());
504         // }
505         // }
506         // } else { // internal JAR
507         // externalArchivesStatus.put(entryPath, INTERNAL_JAR_IGNORE);
508         // }
509         // }
510         // // according to computed status, generate a delta
511         // status = (String)externalArchivesStatus.get(entryPath);
512         // if (status != null){
513         // if (status == EXTERNAL_JAR_ADDED){
514         // PackageFragmentRoot root =
515         // (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
516         // if (VERBOSE){
517         // System.out.println("- External JAR ADDED, affecting root:
518         // "+root.getElementName()); //$NON-NLS-1$
519         // }
520         // elementAdded(root, null, null);
521         // hasDelta = true;
522         // } else if (status == EXTERNAL_JAR_CHANGED) {
523         // PackageFragmentRoot root =
524         // (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
525         // if (VERBOSE){
526         // System.out.println("- External JAR CHANGED, affecting root:
527         // "+root.getElementName()); //$NON-NLS-1$
528         // }
529         // // reset the corresponding project built state, since the builder would
530         // miss this change
531         // this.manager.setLastBuiltState(project.getProject(), null /*no state*/);
532         // contentChanged(root, null);
533         // hasDelta = true;
534         // } else if (status == EXTERNAL_JAR_REMOVED) {
535         // PackageFragmentRoot root =
536         // (PackageFragmentRoot)project.getPackageFragmentRoot(entryPath.toString());
537         // if (VERBOSE){
538         // System.out.println("- External JAR REMOVED, affecting root:
539         // "+root.getElementName()); //$NON-NLS-1$
540         // }
541         // elementRemoved(root, null, null);
542         // hasDelta = true;
543         // }
544         // }
545         // }
546         // }
547         // }
548         // return hasDelta;
549         // }
550         JavaElementDelta currentDelta() {
551                 if (this.currentDelta == null) {
552                         this.currentDelta = new JavaElementDelta(this.manager
553                                         .getJavaModel());
554                 }
555                 return this.currentDelta;
556         }
557
558         /*
559          * Process the given delta and look for projects being added, opened, closed
560          * or with a java nature being added or removed. Note that projects being
561          * deleted are checked in deleting(IProject). In all cases, add the
562          * project's dependents to the list of projects to update so that the
563          * classpath related markers can be updated.
564          */
565         // public void checkProjectsBeingAddedOrRemoved(IResourceDelta delta) {
566         // IResource resource = delta.getResource();
567         // switch (resource.getType()) {
568         // case IResource.ROOT :
569         // // workaround for bug 15168 circular errors not reported
570         // if (this.manager.javaProjectsCache == null) {
571         // try {
572         // this.manager.javaProjectsCache =
573         // this.manager.getJavaModel().getJavaProjects();
574         // } catch (JavaModelException e) {
575         // }
576         // }
577         //                              
578         // IResourceDelta[] children = delta.getAffectedChildren();
579         // for (int i = 0, length = children.length; i < length; i++) {
580         // this.checkProjectsBeingAddedOrRemoved(children[i]);
581         // }
582         // break;
583         // case IResource.PROJECT :
584         // // NB: No need to check project's nature as if the project is not a java
585         // project:
586         // // - if the project is added or changed this is a noop for
587         // projectsBeingDeleted
588         // // - if the project is closed, it has already lost its java nature
589         // int deltaKind = delta.getKind();
590         // if (deltaKind == IResourceDelta.ADDED) {
591         // // remember project and its dependents
592         // IProject project = (IProject)resource;
593         // this.addToProjectsToUpdateWithDependents(project);
594         //                                      
595         // // workaround for bug 15168 circular errors not reported
596         // if (JavaProject.hasJavaNature(project)) {
597         // this.addToParentInfo((JavaProject)JavaCore.create(project));
598         // }
599         //
600         // } else if (deltaKind == IResourceDelta.CHANGED) {
601         // IProject project = (IProject)resource;
602         // if ((delta.getFlags() & IResourceDelta.OPEN) != 0) {
603         // // project opened or closed: remember project and its dependents
604         // this.addToProjectsToUpdateWithDependents(project);
605         //                                              
606         // // workaround for bug 15168 circular errors not reported
607         // if (project.isOpen()) {
608         // if (JavaProject.hasJavaNature(project)) {
609         // this.addToParentInfo((JavaProject)JavaCore.create(project));
610         // }
611         // } else {
612         // JavaProject javaProject =
613         // (JavaProject)this.manager.getJavaModel().findJavaProject(project);
614         // if (javaProject != null) {
615         // try {
616         // javaProject.close();
617         // } catch (JavaModelException e) {
618         // }
619         // this.removeFromParentInfo(javaProject);
620         // }
621         // }
622         // } else if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
623         // boolean wasJavaProject =
624         // this.manager.getJavaModel().findJavaProject(project) != null;
625         // boolean isJavaProject = JavaProject.hasJavaNature(project);
626         // if (wasJavaProject != isJavaProject) {
627         // // java nature added or removed: remember project and its dependents
628         // this.addToProjectsToUpdateWithDependents(project);
629         //
630         // // workaround for bug 15168 circular errors not reported
631         // if (isJavaProject) {
632         // this.addToParentInfo((JavaProject)JavaCore.create(project));
633         // } else {
634         // JavaProject javaProject = (JavaProject)JavaCore.create(project);
635         //                                                              
636         // // flush classpath markers
637         // javaProject.
638         // flushClasspathProblemMarkers(
639         // true, // flush cycle markers
640         // true //flush classpath format markers
641         // );
642         //                                                                      
643         // // remove problems and tasks created by the builder
644         // JavaBuilder.removeProblemsAndTasksFor(project);
645         //
646         // // close project
647         // try {
648         // javaProject.close();
649         // } catch (JavaModelException e) {
650         // }
651         // this.removeFromParentInfo(javaProject);
652         // }
653         // } else {
654         // // in case the project was removed then added then changed (see bug
655         // 19799)
656         // if (JavaProject.hasJavaNature(project)) { // need nature check - 18698
657         // this.addToParentInfo((JavaProject)JavaCore.create(project));
658         // }
659         // }
660         // } else {
661         // // workaround for bug 15168 circular errors not reported
662         // // in case the project was removed then added then changed
663         // if (JavaProject.hasJavaNature(project)) { // need nature check - 18698
664         // this.addToParentInfo((JavaProject)JavaCore.create(project));
665         // }
666         // }
667         // }
668         // break;
669         // }
670         // }
671         // private void checkSourceAttachmentChange(IResourceDelta delta, IResource
672         // res) {
673         // IPath rootPath = (IPath)this.sourceAttachments.get(res.getFullPath());
674         // if (rootPath != null) {
675         // RootInfo rootInfo = this.rootInfo(rootPath, delta.getKind());
676         // if (rootInfo != null) {
677         // IJavaProject projectOfRoot = rootInfo.project;
678         // IPackageFragmentRoot root = null;
679         // try {
680         // // close the root so that source attachement cache is flushed
681         // root = projectOfRoot.findPackageFragmentRoot(rootPath);
682         // if (root != null) {
683         // root.close();
684         // }
685         // } catch (JavaModelException e) {
686         // }
687         // if (root == null) return;
688         // switch (delta.getKind()) {
689         // case IResourceDelta.ADDED:
690         // currentDelta().sourceAttached(root);
691         // break;
692         // case IResourceDelta.CHANGED:
693         // currentDelta().sourceDetached(root);
694         // currentDelta().sourceAttached(root);
695         // break;
696         // case IResourceDelta.REMOVED:
697         // currentDelta().sourceDetached(root);
698         // break;
699         // }
700         // }
701         // }
702         // }
703         /**
704          * Closes the given element, which removes it from the cache of open
705          * elements.
706          */
707         // protected static void close(Openable element) {
708         //
709         // try {
710         // element.close();
711         // } catch (JavaModelException e) {
712         // // do nothing
713         // }
714         // }
715         /**
716          * Generic processing for elements with changed contents:
717          * <ul>
718          * <li>The element is closed such that any subsequent accesses will re-open
719          * the element reflecting its new structure.
720          * <li>An entry is made in the delta reporting a content change (K_CHANGE
721          * with F_CONTENT flag set).
722          * </ul>
723          * Delta argument could be null if processing an external JAR change
724          */
725         // protected void contentChanged(Openable element, IResourceDelta delta) {
726         //
727         // close(element);
728         // int flags = IJavaElementDelta.F_CONTENT;
729         // if (element instanceof JarPackageFragmentRoot){
730         // flags |= IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED;
731         // }
732         // currentDelta().changed(element, flags);
733         // }
734         //      
735         /**
736          * Creates the openables corresponding to this resource. Returns null if
737          * none was found.
738          */
739         // protected Openable createElement(IResource resource, int elementType,
740         // RootInfo rootInfo) {
741         // if (resource == null) return null;
742         //              
743         // IPath path = resource.getFullPath();
744         // IJavaElement element = null;
745         // switch (elementType) {
746         //                      
747         // case IJavaElement.JAVA_PROJECT:
748         //                      
749         // // note that non-java resources rooted at the project level will also
750         // enter this code with
751         // // an elementType JAVA_PROJECT (see #elementType(...)).
752         // if (resource instanceof IProject){
753         //
754         // this.popUntilPrefixOf(path);
755         //                                      
756         // if (this.currentElement != null
757         // && this.currentElement.getElementType() == IJavaElement.JAVA_PROJECT
758         // && ((IJavaProject)this.currentElement).getProject().equals(resource)) {
759         // return this.currentElement;
760         // }
761         // if (rootInfo != null && rootInfo.project.getProject().equals(resource)){
762         // element = (Openable)rootInfo.project;
763         // break;
764         // }
765         // IProject proj = (IProject)resource;
766         // if (JavaProject.hasJavaNature(proj)) {
767         // element = JavaCore.create(proj);
768         // } else {
769         // // java project may have been been closed or removed (look for
770         // // element amongst old java project s list).
771         // element = (Openable) manager.getJavaModel().findJavaProject(proj);
772         // }
773         // }
774         // break;
775         // case IJavaElement.PACKAGE_FRAGMENT_ROOT:
776         // element = rootInfo == null ? JavaCore.create(resource) :
777         // rootInfo.project.getPackageFragmentRoot(resource);
778         // break;
779         // case IJavaElement.PACKAGE_FRAGMENT:
780         // // find the element that encloses the resource
781         // this.popUntilPrefixOf(path);
782         //                              
783         // if (this.currentElement == null) {
784         // element = rootInfo == null ? JavaCore.create(resource) :
785         // JavaModelManager.create(resource, rootInfo.project);
786         // } else {
787         // // find the root
788         // IPackageFragmentRoot root = this.currentElement.getPackageFragmentRoot();
789         // if (root == null) {
790         // element = rootInfo == null ? JavaCore.create(resource) :
791         // JavaModelManager.create(resource, rootInfo.project);
792         // } else if (((JavaProject)root.getJavaProject()).contains(resource)) {
793         // // create package handle
794         // IPath pkgPath = path.removeFirstSegments(root.getPath().segmentCount());
795         // String pkg = ProjectPrefUtil.packageName(pkgPath);
796         // if (pkg == null) return null;
797         // element = root.getPackageFragment(pkg);
798         // }
799         // }
800         // break;
801         // case IJavaElement.COMPILATION_UNIT:
802         // case IJavaElement.CLASS_FILE:
803         // // find the element that encloses the resource
804         // this.popUntilPrefixOf(path);
805         //                              
806         // if (this.currentElement == null) {
807         // element = rootInfo == null ? JavaCore.create(resource) :
808         // JavaModelManager.create(resource, rootInfo.project);
809         // } else {
810         // // find the package
811         // IPackageFragment pkgFragment = null;
812         // switch (this.currentElement.getElementType()) {
813         // case IJavaElement.PACKAGE_FRAGMENT_ROOT:
814         // IPackageFragmentRoot root = (IPackageFragmentRoot)this.currentElement;
815         // IPath rootPath = root.getPath();
816         // IPath pkgPath = path.removeLastSegments(1);
817         // String pkgName =
818         // ProjectPrefUtil.packageName(pkgPath.removeFirstSegments(rootPath.segmentCount()));
819         // if (pkgName != null) {
820         // pkgFragment = root.getPackageFragment(pkgName);
821         // }
822         // break;
823         // case IJavaElement.PACKAGE_FRAGMENT:
824         // Openable pkg = (Openable)this.currentElement;
825         // if (pkg.getPath().equals(path.removeLastSegments(1))) {
826         // pkgFragment = (IPackageFragment)pkg;
827         // } // else case of package x which is a prefix of x.y
828         // break;
829         // case IJavaElement.COMPILATION_UNIT:
830         // case IJavaElement.CLASS_FILE:
831         // pkgFragment = (IPackageFragment)this.currentElement.getParent();
832         // break;
833         // }
834         // if (pkgFragment == null) {
835         // element = rootInfo == null ? JavaCore.create(resource) :
836         // JavaModelManager.create(resource, rootInfo.project);
837         // } else {
838         // if (elementType == IJavaElement.COMPILATION_UNIT) {
839         // // create compilation unit handle
840         // // fileName validation has been done in elementType(IResourceDelta, int,
841         // boolean)
842         // String fileName = path.lastSegment();
843         // element = pkgFragment.getCompilationUnit(fileName);
844         // } else {
845         // // create class file handle
846         // // fileName validation has been done in elementType(IResourceDelta, int,
847         // boolean)
848         // String fileName = path.lastSegment();
849         // element = pkgFragment.getClassFile(fileName);
850         // }
851         // }
852         // }
853         // break;
854         // }
855         // if (element == null) {
856         // return null;
857         // } else {
858         // this.currentElement = (Openable)element;
859         // return this.currentElement;
860         // }
861         // }
862         /**
863          * Note that the project is about to be deleted.
864          */
865         // public void deleting(IProject project) {
866         //              
867         // try {
868         // // discard indexing jobs that belong to this project so that the project
869         // can be
870         // // deleted without interferences from the index manager
871         // this.indexManager.discardJobs(project.getName());
872         //
873         // JavaProject javaProject = (JavaProject)JavaCore.create(project);
874         //                      
875         // // remember roots of this project
876         // if (this.removedRoots == null) {
877         // this.removedRoots = new HashMap();
878         // }
879         // if (javaProject.isOpen()) {
880         // this.removedRoots.put(javaProject,
881         // javaProject.getPackageFragmentRoots());
882         // } else {
883         // // compute roots without opening project
884         // this.removedRoots.put(
885         // javaProject,
886         // javaProject.computePackageFragmentRoots(
887         // javaProject.getResolvedClasspath(true),
888         // false));
889         // }
890         //                      
891         // javaProject.close();
892         //
893         // // workaround for bug 15168 circular errors not reported
894         // if (this.manager.javaProjectsCache == null) {
895         // this.manager.javaProjectsCache =
896         // this.manager.getJavaModel().getJavaProjects();
897         // }
898         // this.removeFromParentInfo(javaProject);
899         //
900         // } catch (JavaModelException e) {
901         // }
902         //              
903         // this.addDependentProjects(project.getFullPath(), this.projectsToUpdate);
904         // }
905
906         /**
907          * Processing for an element that has been added:
908          * <ul>
909          * <li>If the element is a project, do nothing, and do not process
910          * children, as when a project is created it does not yet have any natures -
911          * specifically a java nature.
912          * <li>If the elemet is not a project, process it as added (see
913          * <code>basicElementAdded</code>.
914          * </ul>
915          * Delta argument could be null if processing an external JAR change
916          */
917         // protected void elementAdded(Openable element, IResourceDelta delta,
918         // RootInfo rootInfo) {
919         // int elementType = element.getElementType();
920         //              
921         // if (elementType == IJavaElement.JAVA_PROJECT) {
922         // // project add is handled by JavaProject.configure() because
923         // // when a project is created, it does not yet have a java nature
924         // if (delta != null &&
925         // JavaProject.hasJavaNature((IProject)delta.getResource())) {
926         // addToParentInfo(element);
927         // if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0) {
928         // Openable movedFromElement =
929         // (Openable)element.getJavaModel().getJavaProject(delta.getMovedFromPath().lastSegment());
930         // currentDelta().movedTo(element, movedFromElement);
931         // } else {
932         // currentDelta().added(element);
933         // }
934         // this.projectsToUpdate.add(element);
935         // this.updateRoots(element.getPath(), delta);
936         // this.projectsForDependentNamelookupRefresh.add((JavaProject) element);
937         // }
938         // } else {
939         // addToParentInfo(element);
940         //                      
941         // // Force the element to be closed as it might have been opened
942         // // before the resource modification came in and it might have a new child
943         // // For example, in an IWorkspaceRunnable:
944         // // 1. create a package fragment p using a java model operation
945         // // 2. open package p
946         // // 3. add file X.java in folder p
947         // // When the resource delta comes in, only the addition of p is notified,
948         // // but the package p is already opened, thus its children are not
949         // recomputed
950         // // and it appears empty.
951         // close(element);
952         //                      
953         // if (delta != null && (delta.getFlags() & IResourceDelta.MOVED_FROM) != 0)
954         // {
955         // IPath movedFromPath = delta.getMovedFromPath();
956         // IResource res = delta.getResource();
957         // IResource movedFromRes;
958         // if (res instanceof IFile) {
959         // movedFromRes = res.getWorkspace().getRoot().getFile(movedFromPath);
960         // } else {
961         // movedFromRes = res.getWorkspace().getRoot().getFolder(movedFromPath);
962         // }
963         //                              
964         // // find the element type of the moved from element
965         // RootInfo movedFromInfo = this.enclosingRootInfo(movedFromPath,
966         // IResourceDelta.REMOVED);
967         // int movedFromType =
968         // this.elementType(
969         // movedFromRes,
970         // IResourceDelta.REMOVED,
971         // element.getParent().getElementType(),
972         // movedFromInfo);
973         //                              
974         // // reset current element as it might be inside a nested root
975         // (popUntilPrefixOf() may use the outer root)
976         // this.currentElement = null;
977         //                      
978         // // create the moved from element
979         // Openable movedFromElement =
980         // elementType != IJavaElement.JAVA_PROJECT && movedFromType ==
981         // IJavaElement.JAVA_PROJECT ?
982         // null : // outside classpath
983         // this.createElement(movedFromRes, movedFromType, movedFromInfo);
984         // if (movedFromElement == null) {
985         // // moved from outside classpath
986         // currentDelta().added(element);
987         // } else {
988         // currentDelta().movedTo(element, movedFromElement);
989         // }
990         // } else {
991         // currentDelta().added(element);
992         // }
993         //                      
994         // switch (elementType) {
995         // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
996         // // when a root is added, and is on the classpath, the project must be
997         // updated
998         // JavaProject project = (JavaProject) element.getJavaProject();
999         // this.projectsToUpdate.add(project);
1000         // this.projectsForDependentNamelookupRefresh.add(project);
1001         //                                      
1002         // break;
1003         // case IJavaElement.PACKAGE_FRAGMENT :
1004         // // get rid of namelookup since it holds onto obsolete cached info
1005         // project = (JavaProject) element.getJavaProject();
1006         // try {
1007         // project.getJavaProjectElementInfo().setNameLookup(null);
1008         // this.projectsForDependentNamelookupRefresh.add(project);
1009         // } catch (JavaModelException e) {
1010         // }
1011         // // add subpackages
1012         // if (delta != null){
1013         // PackageFragmentRoot root = element.getPackageFragmentRoot();
1014         // String name = element.getElementName();
1015         // IResourceDelta[] children = delta.getAffectedChildren();
1016         // for (int i = 0, length = children.length; i < length; i++) {
1017         // IResourceDelta child = children[i];
1018         // IResource resource = child.getResource();
1019         // if (resource instanceof IFolder) {
1020         // String folderName = resource.getName();
1021         // if (ProjectPrefUtil.isValidFolderNameForPackage(folderName)) {
1022         // String subpkgName =
1023         // name.length() == 0 ?
1024         // folderName :
1025         // name + "." + folderName; //$NON-NLS-1$
1026         // Openable subpkg = (Openable)root.getPackageFragment(subpkgName);
1027         // this.updateIndex(subpkg, child);
1028         // this.elementAdded(subpkg, child, rootInfo);
1029         // }
1030         // }
1031         // }
1032         // }
1033         // break;
1034         // }
1035         // }
1036         // }
1037         /**
1038          * Generic processing for a removed element:
1039          * <ul>
1040          * <li>Close the element, removing its structure from the cache
1041          * <li>Remove the element from its parent's cache of children
1042          * <li>Add a REMOVED entry in the delta
1043          * </ul>
1044          * Delta argument could be null if processing an external JAR change
1045          */
1046         // protected void elementRemoved(Openable element, IResourceDelta delta,
1047         // RootInfo rootInfo) {
1048         //              
1049         // if (element.isOpen()) {
1050         // close(element);
1051         // }
1052         // removeFromParentInfo(element);
1053         // int elementType = element.getElementType();
1054         // if (delta != null && (delta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
1055         // IPath movedToPath = delta.getMovedToPath();
1056         // IResource res = delta.getResource();
1057         // IResource movedToRes;
1058         // switch (res.getType()) {
1059         // case IResource.PROJECT:
1060         // movedToRes =
1061         // res.getWorkspace().getRoot().getProject(movedToPath.lastSegment());
1062         // break;
1063         // case IResource.FOLDER:
1064         // movedToRes = res.getWorkspace().getRoot().getFolder(movedToPath);
1065         // break;
1066         // case IResource.FILE:
1067         // movedToRes = res.getWorkspace().getRoot().getFile(movedToPath);
1068         // break;
1069         // default:
1070         // return;
1071         // }
1072         //
1073         // // find the element type of the moved from element
1074         // RootInfo movedToInfo = this.enclosingRootInfo(movedToPath,
1075         // IResourceDelta.ADDED);
1076         // int movedToType =
1077         // this.elementType(
1078         // movedToRes,
1079         // IResourceDelta.ADDED,
1080         // element.getParent().getElementType(),
1081         // movedToInfo);
1082         //
1083         // // reset current element as it might be inside a nested root
1084         // (popUntilPrefixOf() may use the outer root)
1085         // this.currentElement = null;
1086         //                      
1087         // // create the moved To element
1088         // Openable movedToElement =
1089         // elementType != IJavaElement.JAVA_PROJECT && movedToType ==
1090         // IJavaElement.JAVA_PROJECT ?
1091         // null : // outside classpath
1092         // this.createElement(movedToRes, movedToType, movedToInfo);
1093         // if (movedToElement == null) {
1094         // // moved outside classpath
1095         // currentDelta().removed(element);
1096         // } else {
1097         // currentDelta().movedFrom(element, movedToElement);
1098         // }
1099         // } else {
1100         // currentDelta().removed(element);
1101         // }
1102         //
1103         // switch (elementType) {
1104         // case IJavaElement.JAVA_MODEL :
1105         // this.indexManager.reset();
1106         // break;
1107         // case IJavaElement.JAVA_PROJECT :
1108         // this.manager.removePerProjectInfo(
1109         // (JavaProject) element);
1110         // this.updateRoots(element.getPath(), delta);
1111         // this.projectsForDependentNamelookupRefresh.add((JavaProject) element);
1112         // break;
1113         // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
1114         // JavaProject project = (JavaProject) element.getJavaProject();
1115         // this.projectsToUpdate.add(project);
1116         // this.projectsForDependentNamelookupRefresh.add(project);
1117         // break;
1118         // case IJavaElement.PACKAGE_FRAGMENT :
1119         // //1G1TW2T - get rid of namelookup since it holds onto obsolete cached
1120         // info
1121         // project = (JavaProject) element.getJavaProject();
1122         // try {
1123         // project.getJavaProjectElementInfo().setNameLookup(null);
1124         // this.projectsForDependentNamelookupRefresh.add(project);
1125         // } catch (JavaModelException e) {
1126         // }
1127         // // remove subpackages
1128         // if (delta != null){
1129         // PackageFragmentRoot root = element.getPackageFragmentRoot();
1130         // String name = element.getElementName();
1131         // IResourceDelta[] children = delta.getAffectedChildren();
1132         // for (int i = 0, length = children.length; i < length; i++) {
1133         // IResourceDelta child = children[i];
1134         // IResource resource = child.getResource();
1135         // if (resource instanceof IFolder) {
1136         // String folderName = resource.getName();
1137         // if (ProjectPrefUtil.isValidFolderNameForPackage(folderName)) {
1138         // String subpkgName =
1139         // name.length() == 0 ?
1140         // folderName :
1141         // name + "." + folderName; //$NON-NLS-1$
1142         // Openable subpkg = (Openable)root.getPackageFragment(subpkgName);
1143         // this.updateIndex(subpkg, child);
1144         // this.elementRemoved(subpkg, child, rootInfo);
1145         // }
1146         // }
1147         // }
1148         // }
1149         // break;
1150         // }
1151         // }
1152         /*
1153          * Returns the type of the java element the given delta matches to. Returns
1154          * NON_JAVA_RESOURCE if unknown (e.g. a non-java resource or excluded .java
1155          * file)
1156          */
1157         // private int elementType(IResource res, int kind, int parentType, RootInfo
1158         // rootInfo) {
1159         // switch (parentType) {
1160         // case IJavaElement.JAVA_MODEL:
1161         // // case of a movedTo or movedFrom project (other cases are handled in
1162         // processResourceDelta(...)
1163         // return IJavaElement.JAVA_PROJECT;
1164         // case NON_JAVA_RESOURCE:
1165         // case IJavaElement.JAVA_PROJECT:
1166         // if (rootInfo == null) {
1167         // rootInfo = this.enclosingRootInfo(res.getFullPath(), kind);
1168         // }
1169         // if (rootInfo != null && rootInfo.isRootOfProject(res.getFullPath())) {
1170         // return IJavaElement.PACKAGE_FRAGMENT_ROOT;
1171         // } else {
1172         // return NON_JAVA_RESOURCE; // not yet in a package fragment root or root
1173         // of another project
1174         // }
1175         // case IJavaElement.PACKAGE_FRAGMENT_ROOT:
1176         // case IJavaElement.PACKAGE_FRAGMENT:
1177         // if (rootInfo == null) {
1178         // rootInfo = this.enclosingRootInfo(res.getFullPath(), kind);
1179         // }
1180         // if (rootInfo == null || ProjectPrefUtil.isExcluded(res,
1181         // rootInfo.exclusionPatterns)) {
1182         // return NON_JAVA_RESOURCE;
1183         // }
1184         // if (res instanceof IFolder) {
1185         // if (ProjectPrefUtil.isValidFolderNameForPackage(res.getName())) {
1186         // return IJavaElement.PACKAGE_FRAGMENT;
1187         // } else {
1188         // return NON_JAVA_RESOURCE;
1189         // }
1190         // } else {
1191         // String fileName = res.getName();
1192         // if (ProjectPrefUtil.isValidCompilationUnitName(fileName)) {
1193         // return IJavaElement.COMPILATION_UNIT;
1194         // } else if (ProjectPrefUtil.isValidClassFileName(fileName)) {
1195         // return IJavaElement.CLASS_FILE;
1196         // } else if (this.rootInfo(res.getFullPath(), kind) != null) {
1197         // // case of proj=src=bin and resource is a jar file on the classpath
1198         // return IJavaElement.PACKAGE_FRAGMENT_ROOT;
1199         // } else {
1200         // return NON_JAVA_RESOURCE;
1201         // }
1202         // }
1203         // default:
1204         // return NON_JAVA_RESOURCE;
1205         // }
1206         // }
1207         /**
1208          * Answer a combination of the lastModified stamp and the size. Used for
1209          * detecting external JAR changes
1210          */
1211         public static long getTimeStamp(File file) {
1212                 return file.lastModified() + file.length();
1213         }
1214
1215         public void initializeRoots() {
1216                 // remember roots infos as old roots infos
1217                 this.oldRoots = this.roots == null ? new HashMap() : this.roots;
1218                 this.oldOtherRoots = this.otherRoots == null ? new HashMap()
1219                                 : this.otherRoots;
1220
1221                 // recompute root infos only if necessary
1222                 if (!rootsAreStale)
1223                         return;
1224
1225                 this.roots = new HashMap();
1226                 this.otherRoots = new HashMap();
1227                 this.sourceAttachments = new HashMap();
1228
1229                 IJavaModel model = this.manager.getJavaModel();
1230                 IJavaProject[] projects;
1231                 try {
1232                         projects = model.getJavaProjects();
1233                 } catch (JavaModelException e) {
1234                         // nothing can be done
1235                         return;
1236                 }
1237                 for (int i = 0, length = projects.length; i < length; i++) {
1238                         IJavaProject project = projects[i];
1239                         IClasspathEntry[] classpath;
1240                         try {
1241                                 classpath = project.getResolvedClasspath(true);
1242                         } catch (JavaModelException e) {
1243                                 // continue with next project
1244                                 continue;
1245                         }
1246                         for (int j = 0, classpathLength = classpath.length; j < classpathLength; j++) {
1247                                 IClasspathEntry entry = classpath[j];
1248                                 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
1249                                         continue;
1250
1251                                 // root path
1252                                 IPath path = entry.getPath();
1253                                 if (this.roots.get(path) == null) {
1254                                         this.roots.put(path, new RootInfo(project, path,
1255                                                         ((ClasspathEntry) entry)
1256                                                                         .fullExclusionPatternChars()));
1257                                 } else {
1258                                         ArrayList rootList = (ArrayList) this.otherRoots.get(path);
1259                                         if (rootList == null) {
1260                                                 rootList = new ArrayList();
1261                                                 this.otherRoots.put(path, rootList);
1262                                         }
1263                                         rootList.add(new RootInfo(project, path,
1264                                                         ((ClasspathEntry) entry)
1265                                                                         .fullExclusionPatternChars()));
1266                                 }
1267
1268                                 // source attachment path
1269                                 if (entry.getEntryKind() != IClasspathEntry.CPE_LIBRARY)
1270                                         continue;
1271                                 QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID,
1272                                                 "sourceattachment: " + path.toOSString()); //$NON-NLS-1$;
1273                                 String propertyString = null;
1274                                 try {
1275                                         propertyString = ResourcesPlugin.getWorkspace().getRoot()
1276                                                         .getPersistentProperty(qName);
1277                                 } catch (CoreException e) {
1278                                         continue;
1279                                 }
1280                                 IPath sourceAttachmentPath;
1281                                 // if (propertyString != null) {
1282                                 // int index=
1283                                 // propertyString.lastIndexOf(JarPackageFragmentRoot.ATTACHMENT_PROPERTY_DELIMITER);
1284                                 // sourceAttachmentPath = (index < 0) ? new Path(propertyString)
1285                                 // : new Path(propertyString.substring(0, index));
1286                                 // } else {
1287                                 sourceAttachmentPath = entry.getSourceAttachmentPath();
1288                                 // }
1289                                 if (sourceAttachmentPath != null) {
1290                                         this.sourceAttachments.put(sourceAttachmentPath, path);
1291                                 }
1292                         }
1293                 }
1294                 this.rootsAreStale = false;
1295         }
1296
1297         /*
1298          * Returns whether a given delta contains some information relevant to the
1299          * JavaModel, in particular it will not consider SYNC or MARKER only deltas.
1300          */
1301         public boolean isAffectedBy(IResourceDelta rootDelta) {
1302                 // if (rootDelta == null) System.out.println("NULL DELTA");
1303                 // long start = System.currentTimeMillis();
1304                 if (rootDelta != null) {
1305                         // use local exception to quickly escape from delta traversal
1306                         class FoundRelevantDeltaException extends RuntimeException {
1307                         }
1308                         try {
1309                                 rootDelta.accept(new IResourceDeltaVisitor() {
1310                                         public boolean visit(IResourceDelta delta)
1311                                                         throws CoreException {
1312                                                 switch (delta.getKind()) {
1313                                                 case IResourceDelta.ADDED:
1314                                                 case IResourceDelta.REMOVED:
1315                                                         throw new FoundRelevantDeltaException();
1316                                                 case IResourceDelta.CHANGED:
1317                                                         // if any flag is set but SYNC or MARKER, this delta
1318                                                         // should be considered
1319                                                         if (delta.getAffectedChildren().length == 0 // only
1320                                                                                                                                                 // check
1321                                                                                                                                                 // leaf
1322                                                                                                                                                 // delta
1323                                                                                                                                                 // nodes
1324                                                                         && (delta.getFlags() & ~(IResourceDelta.SYNC | IResourceDelta.MARKERS)) != 0) {
1325                                                                 throw new FoundRelevantDeltaException();
1326                                                         }
1327                                                 }
1328                                                 return true;
1329                                         }
1330                                 });
1331                         } catch (FoundRelevantDeltaException e) {
1332                                 // System.out.println("RELEVANT DELTA detected in: "+
1333                                 // (System.currentTimeMillis() - start));
1334                                 return true;
1335                         } catch (CoreException e) { // ignore delta if not able to traverse
1336                         }
1337                 }
1338                 // System.out.println("IGNORE SYNC DELTA took: "+
1339                 // (System.currentTimeMillis() - start));
1340                 return false;
1341         }
1342
1343         /*
1344          * Returns whether the given resource is in one of the given output folders
1345          * and if it is filtered out from this output folder.
1346          */
1347         private boolean isResFilteredFromOutput(OutputsInfo info, IResource res,
1348                         int elementType) {
1349                 if (info != null) {
1350                         IPath resPath = res.getFullPath();
1351                         for (int i = 0; i < info.outputCount; i++) {
1352                                 if (info.paths[i].isPrefixOf(resPath)) {
1353                                         if (info.traverseModes[i] != IGNORE) {
1354                                                 // case of bin=src
1355                                                 if (info.traverseModes[i] == SOURCE
1356                                                                 && elementType == IJavaElement.CLASS_FILE) {
1357                                                         return true;
1358                                                 } else {
1359                                                         // case of .class file under project and no source
1360                                                         // folder
1361                                                         // proj=bin
1362                                                         if (elementType == IJavaElement.JAVA_PROJECT
1363                                                                         && res instanceof IFile
1364                                                                         && PHPFileUtil.isPHPFile((IFile) res)) {
1365                                                                 return true;
1366                                                         }
1367                                                 }
1368                                         } else {
1369                                                 return true;
1370                                         }
1371                                 }
1372                         }
1373                 }
1374                 return false;
1375         }
1376
1377         /*
1378          * Merges all awaiting deltas.
1379          */
1380         private IJavaElementDelta mergeDeltas(Collection deltas) {
1381                 if (deltas.size() == 0)
1382                         return null;
1383                 if (deltas.size() == 1)
1384                         return (IJavaElementDelta) deltas.iterator().next();
1385
1386                 if (VERBOSE) {
1387                         System.out
1388                                         .println("MERGING " + deltas.size() + " DELTAS [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1389                 }
1390
1391                 Iterator iterator = deltas.iterator();
1392                 JavaElementDelta rootDelta = new JavaElementDelta(
1393                                 this.manager.javaModel);
1394                 boolean insertedTree = false;
1395                 while (iterator.hasNext()) {
1396                         JavaElementDelta delta = (JavaElementDelta) iterator.next();
1397                         if (VERBOSE) {
1398                                 System.out.println(delta.toString());
1399                         }
1400                         IJavaElement element = delta.getElement();
1401                         if (this.manager.javaModel.equals(element)) {
1402                                 IJavaElementDelta[] children = delta.getAffectedChildren();
1403                                 for (int j = 0; j < children.length; j++) {
1404                                         JavaElementDelta projectDelta = (JavaElementDelta) children[j];
1405                                         rootDelta.insertDeltaTree(projectDelta.getElement(),
1406                                                         projectDelta);
1407                                         insertedTree = true;
1408                                 }
1409                                 IResourceDelta[] resourceDeltas = delta.getResourceDeltas();
1410                                 if (resourceDeltas != null) {
1411                                         for (int i = 0, length = resourceDeltas.length; i < length; i++) {
1412                                                 rootDelta.addResourceDelta(resourceDeltas[i]);
1413                                                 insertedTree = true;
1414                                         }
1415                                 }
1416                         } else {
1417                                 rootDelta.insertDeltaTree(element, delta);
1418                                 insertedTree = true;
1419                         }
1420                 }
1421                 if (insertedTree)
1422                         return rootDelta;
1423                 return null;
1424         }
1425
1426         /**
1427          * Check whether the updated file is affecting some of the properties of a
1428          * given project (like its classpath persisted as a file). Also force
1429          * classpath problems to be refresh if not running in autobuild mode. NOTE:
1430          * It can induce resource changes, and cannot be called during POST_CHANGE
1431          * notification.
1432          * 
1433          */
1434         // public void performPreBuildCheck(
1435         // IResourceDelta delta,
1436         // IJavaElement parent) {
1437         //      
1438         // IResource resource = delta.getResource();
1439         // IJavaElement element = null;
1440         // boolean processChildren = false;
1441         //      
1442         // switch (resource.getType()) {
1443         //      
1444         // case IResource.ROOT :
1445         // if (delta.getKind() == IResourceDelta.CHANGED) {
1446         // element = JavaCore.create(resource);
1447         // processChildren = true;
1448         // }
1449         // break;
1450         // case IResource.PROJECT :
1451         // int kind = delta.getKind();
1452         // switch (kind) {
1453         // case IResourceDelta.CHANGED:
1454         // // do not visit non-java projects (see bug 16140 Non-java project gets
1455         // .classpath)
1456         // IProject project = (IProject)resource;
1457         // if (JavaProject.hasJavaNature(project)) {
1458         // element = JavaCore.create(resource);
1459         // processChildren = true;
1460         // } else if
1461         // (JavaModelManager.getJavaModelManager().getJavaModel().findJavaProject(project)
1462         // != null) {
1463         // // project had the java nature
1464         // this.rootsAreStale = true;
1465         //
1466         // // remove classpath cache so that initializeRoots() will not consider the
1467         // project has a classpath
1468         // this.manager.removePerProjectInfo((JavaProject)JavaCore.create(project));
1469         // }
1470         // break;
1471         // case IResourceDelta.ADDED:
1472         // this.rootsAreStale = true;
1473         // break;
1474         // case IResourceDelta.REMOVED:
1475         // // remove classpath cache so that initializeRoots() will not consider the
1476         // project has a classpath
1477         // this.manager.removePerProjectInfo((JavaProject)JavaCore.create(resource));
1478         //                                              
1479         // this.rootsAreStale = true;
1480         // break;
1481         // }
1482         // break;
1483         // case IResource.FILE :
1484         // if (parent.getElementType() == IJavaElement.JAVA_PROJECT) {
1485         // IFile file = (IFile) resource;
1486         // JavaProject project = (JavaProject) parent;
1487         //      
1488         // /* check classpath file change */
1489         // if (file.getName().equals(JavaProject.CLASSPATH_FILENAME)) {
1490         // reconcileClasspathFileUpdate(delta, file, project);
1491         // this.rootsAreStale = true;
1492         // break;
1493         // }
1494         // // /* check custom preference file change */
1495         // // if (file.getName().equals(JavaProject.PREF_FILENAME)) {
1496         // // reconcilePreferenceFileUpdate(delta, file, project);
1497         // // break;
1498         // // }
1499         // }
1500         // break;
1501         // }
1502         // if (processChildren) {
1503         // IResourceDelta[] children = delta.getAffectedChildren();
1504         // for (int i = 0; i < children.length; i++) {
1505         // performPreBuildCheck(children[i], element);
1506         // }
1507         // }
1508         // }
1509         // private void popUntilPrefixOf(IPath path) {
1510         // while (this.currentElement != null) {
1511         // IPath currentElementPath = null;
1512         // if (this.currentElement instanceof IPackageFragmentRoot) {
1513         // currentElementPath =
1514         // ((IPackageFragmentRoot)this.currentElement).getPath();
1515         // } else {
1516         // IResource currentElementResource = this.currentElement.getResource();
1517         // if (currentElementResource != null) {
1518         // currentElementPath = currentElementResource.getFullPath();
1519         // }
1520         // }
1521         // if (currentElementPath != null) {
1522         // if (this.currentElement instanceof IPackageFragment
1523         // && this.currentElement.getElementName().length() == 0
1524         // && currentElementPath.segmentCount() != path.segmentCount()-1) {
1525         // // default package and path is not a direct child
1526         // this.currentElement = (Openable)this.currentElement.getParent();
1527         // }
1528         // if (currentElementPath.isPrefixOf(path)) {
1529         // return;
1530         // }
1531         // }
1532         // this.currentElement = (Openable)this.currentElement.getParent();
1533         // }
1534         // }
1535         /**
1536          * Converts a <code>IResourceDelta</code> rooted in a
1537          * <code>Workspace</code> into the corresponding set of
1538          * <code>IJavaElementDelta</code>, rooted in the relevant
1539          * <code>JavaModel</code>s.
1540          */
1541
1542         /**
1543          * Update the JavaModel according to a .classpath file change. The file can
1544          * have changed as a result of a previous call to
1545          * JavaProject#setRawClasspath or as a result of some user update (through
1546          * repository)
1547          */
1548         // void reconcileClasspathFileUpdate(IResourceDelta delta, IFile file,
1549         // JavaProject project) {
1550         //                      
1551         // switch (delta.getKind()) {
1552         // case IResourceDelta.REMOVED : // recreate one based on in-memory
1553         // classpath
1554         // try {
1555         // JavaModelManager.PerProjectInfo info =
1556         // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project.getProject());
1557         // if (info.classpath != null) { // if there is an in-memory classpath
1558         // project.saveClasspath(info.classpath, info.outputLocation);
1559         // }
1560         // } catch (JavaModelException e) {
1561         // if (project.getProject().isAccessible()) {
1562         // ProjectPrefUtil.log(e, "Could not save classpath for "+
1563         // project.getPath()); //$NON-NLS-1$
1564         // }
1565         // }
1566         // break;
1567         // case IResourceDelta.CHANGED :
1568         // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0 // only consider
1569         // content change
1570         // && (delta.getFlags() & IResourceDelta.MOVED_FROM) == 0) // and also move
1571         // and overide scenario (see
1572         // http://dev.eclipse.org/bugs/show_bug.cgi?id=21420)
1573         // break;
1574         // case IResourceDelta.ADDED :
1575         // // check if any actual difference
1576         // project.flushClasspathProblemMarkers(false, true);
1577         // boolean wasSuccessful = false; // flag recording if .classpath file
1578         // change got reflected
1579         // try {
1580         // // force to (re)read the property file
1581         // IClasspathEntry[] fileEntries = project.readClasspathFile(true/*create
1582         // markers*/, false/*don't log problems*/);
1583         // if (fileEntries == null)
1584         // break; // could not read, ignore
1585         // JavaModelManager.PerProjectInfo info =
1586         // JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project.getProject());
1587         // if (info.classpath != null) { // if there is an in-memory classpath
1588         // if (project.isClasspathEqualsTo(info.classpath, info.outputLocation,
1589         // fileEntries)) {
1590         // wasSuccessful = true;
1591         // break;
1592         // }
1593         // }
1594         //              
1595         // // will force an update of the classpath/output location based on the
1596         // file information
1597         // // extract out the output location
1598         // IPath outputLocation = null;
1599         // if (fileEntries != null && fileEntries.length > 0) {
1600         // IClasspathEntry entry = fileEntries[fileEntries.length - 1];
1601         // if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1602         // outputLocation = entry.getPath();
1603         // IClasspathEntry[] copy = new IClasspathEntry[fileEntries.length - 1];
1604         // System.arraycopy(fileEntries, 0, copy, 0, copy.length);
1605         // fileEntries = copy;
1606         // }
1607         // }
1608         // // restore output location
1609         // if (outputLocation == null) {
1610         // outputLocation = SetClasspathOperation.ReuseOutputLocation;
1611         // // clean mode will also default to reusing current one
1612         // }
1613         // project.setRawClasspath(
1614         // fileEntries,
1615         // outputLocation,
1616         // null, // monitor
1617         // true, // canChangeResource
1618         // project.getResolvedClasspath(true), // ignoreUnresolvedVariable
1619         // true, // needValidation
1620         // false); // no need to save
1621         //                                      
1622         // // if reach that far, the classpath file change got absorbed
1623         // wasSuccessful = true;
1624         // } catch (RuntimeException e) {
1625         // // setRawClasspath might fire a delta, and a listener may throw an
1626         // exception
1627         // if (project.getProject().isAccessible()) {
1628         // ProjectPrefUtil.log(e, "Could not set classpath for "+
1629         // project.getPath()); //$NON-NLS-1$
1630         // }
1631         // break;
1632         // } catch (JavaModelException e) { // CP failed validation
1633         // if (project.getProject().isAccessible()) {
1634         // if (e.getJavaModelStatus().getException() instanceof CoreException) {
1635         // // happens if the .classpath could not be written to disk
1636         // project.createClasspathProblemMarker(new JavaModelStatus(
1637         // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1638         // ProjectPrefUtil.bind("classpath.couldNotWriteClasspathFile",
1639         // project.getElementName(), e.getMessage()))); //$NON-NLS-1$
1640         // } else {
1641         // project.createClasspathProblemMarker(new JavaModelStatus(
1642         // IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1643         // ProjectPrefUtil.bind("classpath.invalidClasspathInClasspathFile",
1644         // project.getElementName(), e.getMessage()))); //$NON-NLS-1$
1645         // }
1646         // }
1647         // break;
1648         // } finally {
1649         // if (!wasSuccessful) {
1650         // try {
1651         // project.setRawClasspath0(JavaProject.INVALID_CLASSPATH);
1652         // project.updatePackageFragmentRoots();
1653         // } catch (JavaModelException e) {
1654         // }
1655         // }
1656         // }
1657         // }
1658         // }
1659         /**
1660          * Update the JavaModel according to a .jprefs file change. The file can
1661          * have changed as a result of a previous call to JavaProject#setOptions or
1662          * as a result of some user update (through repository) Unused until
1663          * preference file get shared (.jpref)
1664          */
1665         // void reconcilePreferenceFileUpdate(IResourceDelta delta, IFile file,
1666         // JavaProject project) {
1667         //                      
1668         // switch (delta.getKind()) {
1669         // case IResourceDelta.REMOVED : // flush project custom settings
1670         // project.setOptions(null);
1671         // return;
1672         // case IResourceDelta.CHANGED :
1673         // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0 // only consider
1674         // content change
1675         // && (delta.getFlags() & IResourceDelta.MOVED_FROM) == 0) // and also move
1676         // and overide scenario
1677         // break;
1678         // identityCheck : { // check if any actual difference
1679         // // force to (re)read the property file
1680         // Preferences filePreferences = project.loadPreferences();
1681         // if (filePreferences == null){
1682         // project.setOptions(null); // should have got removed delta.
1683         // return;
1684         // }
1685         // Preferences projectPreferences = project.getPreferences();
1686         // if (projectPreferences == null) return; // not a Java project
1687         //                                              
1688         // // compare preferences set to their default
1689         // String[] defaultProjectPropertyNames =
1690         // projectPreferences.defaultPropertyNames();
1691         // String[] defaultFilePropertyNames =
1692         // filePreferences.defaultPropertyNames();
1693         // if (defaultProjectPropertyNames.length ==
1694         // defaultFilePropertyNames.length) {
1695         // for (int i = 0; i < defaultProjectPropertyNames.length; i++){
1696         // String propertyName = defaultProjectPropertyNames[i];
1697         // if
1698         // (!projectPreferences.getString(propertyName).trim().equals(filePreferences.getString(propertyName).trim())){
1699         // break identityCheck;
1700         // }
1701         // }
1702         // } else break identityCheck;
1703         //
1704         // // compare custom preferences not set to their default
1705         // String[] projectPropertyNames = projectPreferences.propertyNames();
1706         // String[] filePropertyNames = filePreferences.propertyNames();
1707         // if (projectPropertyNames.length == filePropertyNames.length) {
1708         // for (int i = 0; i < projectPropertyNames.length; i++){
1709         // String propertyName = projectPropertyNames[i];
1710         // if
1711         // (!projectPreferences.getString(propertyName).trim().equals(filePreferences.getString(propertyName).trim())){
1712         // break identityCheck;
1713         // }
1714         // }
1715         // } else break identityCheck;
1716         //                                      
1717         // // identical - do nothing
1718         // return;
1719         // }
1720         // case IResourceDelta.ADDED :
1721         // // not identical, create delta and reset cached preferences
1722         // project.setPreferences(null);
1723         // // create delta
1724         // //fCurrentDelta.changed(project, IJavaElementDelta.F_OPTIONS_CHANGED);
1725         // }
1726         // }
1727         /*
1728          * Registers the given delta with this delta processor.
1729          */
1730         public void registerJavaModelDelta(IJavaElementDelta delta) {
1731                 this.javaModelDeltas.add(delta);
1732         }
1733
1734         /**
1735          * Removes the given element from its parents cache of children. If the
1736          * element does not have a parent, or the parent is not currently open, this
1737          * has no effect.
1738          */
1739         protected void removeFromParentInfo(Openable child) {
1740
1741                 Openable parent = (Openable) child.getParent();
1742                 if (parent != null && parent.isOpen()) {
1743                         try {
1744                                 JavaElementInfo info = (JavaElementInfo) parent
1745                                                 .getElementInfo();
1746                                 info.removeChild(child);
1747                         } catch (JavaModelException e) {
1748                                 // do nothing - we already checked if open
1749                         }
1750                 }
1751         }
1752
1753         /**
1754          * Notification that some resource changes have happened on the platform,
1755          * and that the Java Model should update any required internal structures
1756          * such that its elements remain consistent. Translates
1757          * <code>IResourceDeltas</code> into <code>IJavaElementDeltas</code>.
1758          * 
1759          * @see IResourceDelta
1760          * @see IResource
1761          */
1762         public void resourceChanged(IResourceChangeEvent event) {
1763                 if (event.getSource() instanceof IWorkspace) {
1764                         int eventType = this.overridenEventType == -1 ? event.getType()
1765                                         : this.overridenEventType;
1766                         IResource resource = event.getResource();
1767                         IResourceDelta delta = event.getDelta();
1768
1769                         switch (eventType) {
1770                         case IResourceChangeEvent.PRE_DELETE:
1771                                 try {
1772                                         if (resource.getType() == IResource.PROJECT
1773                                                         && ((IProject) resource)
1774                                                                         .hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
1775
1776                                                 deleting((IProject) resource);
1777                                         }
1778                                 } catch (CoreException e) {
1779                                         // project doesn't exist or is not open: ignore
1780                                 }
1781                                 return;
1782
1783                         case IResourceChangeEvent.POST_CHANGE:
1784                                 if (isAffectedBy(delta)) { // avoid populating for SYNC or
1785                                                                                         // MARKER deltas
1786                                         try {
1787                                                 try {
1788                                                         stopDeltas();
1789                                                         // checkProjectsBeingAddedOrRemoved(delta);
1790                                                         // if (this.refreshedElements != null) {
1791                                                         // createExternalArchiveDelta(null);
1792                                                         // }
1793                                                         IJavaElementDelta translatedDelta = processResourceDelta(delta);
1794                                                         if (translatedDelta != null) {
1795                                                                 registerJavaModelDelta(translatedDelta);
1796                                                         }
1797                                                 } finally {
1798                                                         startDeltas();
1799                                                 }
1800                                                 // notifyTypeHierarchies(this.state.elementChangedListeners,
1801                                                 // this.state.elementChangedListenerCount);
1802                                                 fire(null, ElementChangedEvent.POST_CHANGE);
1803                                         } finally {
1804                                                 // workaround for bug 15168 circular errors not reported
1805                                                 this.state.modelProjectsCache = null;
1806                                                 this.removedRoots = null;
1807                                         }
1808                                 }
1809                                 return;
1810
1811                         case IResourceChangeEvent.PRE_BUILD:
1812                                 DeltaProcessingState.ProjectUpdateInfo[] updates = this.state
1813                                                 .removeAllProjectUpdates();
1814                                 if (updates != null) {
1815                                         for (int i = 0, length = updates.length; i < length; i++) {
1816                                                 try {
1817                                                         updates[i].updateProjectReferencesIfNecessary();
1818                                                 } catch (JavaModelException e) {
1819                                                         // do nothing
1820                                                 }
1821                                         }
1822                                 }
1823                                 // this.processPostChange = false;
1824                                 if (isAffectedBy(delta)) { // avoid populating for SYNC or
1825                                                                                         // MARKER deltas
1826                                 // updateClasspathMarkers(delta);
1827                                         PHPBuilder.buildStarting();
1828                                 }
1829                                 // does not fire any deltas
1830                                 return;
1831
1832                         case IResourceChangeEvent.POST_BUILD:
1833                                 PHPBuilder.buildFinished();
1834                                 return;
1835                         }
1836                 }
1837                 // // jsurfer TODO compare 3.0 sources
1838                 // if (event.getSource() instanceof IWorkspace) {
1839                 // int eventType = this.overridenEventType == -1 ? event.getType() :
1840                 // this.overridenEventType;
1841                 // IResource resource = event.getResource();
1842                 // IResourceDelta delta = event.getDelta();
1843                 //                      
1844                 // switch(eventType){
1845                 // case IResourceChangeEvent.PRE_DELETE :
1846                 // try {
1847                 // if(resource.getType() == IResource.PROJECT
1848                 // && ((IProject) resource).hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
1849                 // // TODO jsurfer temp-del
1850                 // // this.deleting((IProject)resource);
1851                 // }
1852                 // } catch(CoreException e){
1853                 // }
1854                 // return;
1855                 //                                      
1856                 // case IResourceChangeEvent.PRE_BUILD :
1857                 // // TODO jsurfer temp-del
1858                 // // if(isAffectedBy(delta)) { // avoid populating for SYNC or MARKER
1859                 // deltas
1860                 // // this.checkProjectsBeingAddedOrRemoved(delta);
1861                 // //
1862                 // // // update the classpath related markers
1863                 // // this.updateClasspathMarkers();
1864                 // //
1865                 // // // the following will close project if affected by the property
1866                 // file change
1867                 // // try {
1868                 // // // don't fire classpath change deltas right away, but batch them
1869                 // // this.manager.stopDeltas();
1870                 // // this.performPreBuildCheck(delta, null);
1871                 // // } finally {
1872                 // // this.manager.startDeltas();
1873                 // // }
1874                 // // }
1875                 // // only fire already computed deltas (resource ones will be processed
1876                 // in post change only)
1877                 // this.manager.fire(null, ElementChangedEvent.PRE_AUTO_BUILD);
1878                 // break;
1879                 //
1880                 // case IResourceChangeEvent.POST_BUILD :
1881                 // // TODO jsurfer temp-del
1882                 // // JavaBuilder.finishedBuilding(event);
1883                 // break;
1884                 //                                      
1885                 // case IResourceChangeEvent.POST_CHANGE :
1886                 // // TODO jsurfer temp-del
1887                 // // if (isAffectedBy(delta)) {
1888                 // // try {
1889                 // // if (this.refreshedElements != null) {
1890                 // // try {
1891                 // // createExternalArchiveDelta(null);
1892                 // // } catch (JavaModelException e) {
1893                 // // e.printStackTrace();
1894                 // // }
1895                 // // }
1896                 // // IJavaElementDelta translatedDelta =
1897                 // this.processResourceDelta(delta);
1898                 // // if (translatedDelta != null) {
1899                 // // this.manager.registerJavaModelDelta(translatedDelta);
1900                 // // }
1901                 // // this.manager.fire(null, ElementChangedEvent.POST_CHANGE);
1902                 // // } finally {
1903                 // // // workaround for bug 15168 circular errors not reported
1904                 // // this.manager.javaProjectsCache = null;
1905                 // // this.removedRoots = null;
1906                 // // }
1907                 // // }
1908                 // }
1909                 // }
1910         }
1911
1912         /*
1913          * Turns the firing mode to on. That is, deltas that are/have been
1914          * registered will be fired.
1915          */
1916         private void startDeltas() {
1917                 this.isFiring = true;
1918         }
1919
1920         /*
1921          * Turns the firing mode to off. That is, deltas that are/have been
1922          * registered will not be fired until deltas are started again.
1923          */
1924         private void stopDeltas() {
1925                 this.isFiring = false;
1926         }
1927
1928         /*
1929          * Note that the project is about to be deleted.
1930          */
1931         private void deleting(IProject project) {
1932
1933                 try {
1934                         // discard indexing jobs that belong to this project so that the
1935                         // project can be
1936                         // deleted without interferences from the index manager
1937                         // this.manager.indexManager.discardJobs(project.getName());
1938
1939                         JavaProject javaProject = (JavaProject) JavaCore.create(project);
1940
1941                         // remember roots of this project
1942                         if (this.removedRoots == null) {
1943                                 this.removedRoots = new HashMap();
1944                         }
1945                         if (javaProject.isOpen()) {
1946                                 this.removedRoots.put(javaProject, javaProject
1947                                                 .getPackageFragmentRoots());
1948                         } else {
1949                                 // compute roots without opening project
1950                                 // this.removedRoots.put(
1951                                 // javaProject,
1952                                 // javaProject.computePackageFragmentRoots(
1953                                 // javaProject.getResolvedClasspath(true/*ignoreUnresolvedEntry*/,
1954                                 // false/*don't generateMarkerOnError*/, false/*don't
1955                                 // returnResolutionInProgress*/),
1956                                 // false));
1957                         }
1958
1959                         javaProject.close();
1960
1961                         // workaround for bug 15168 circular errors not reported
1962                         if (this.state.modelProjectsCache == null) {
1963                                 this.state.modelProjectsCache = this.manager.getJavaModel()
1964                                                 .getJavaProjects();
1965                         }
1966                         this.removeFromParentInfo(javaProject);
1967
1968                 } catch (JavaModelException e) {
1969                         // java project doesn't exist: ignore
1970                 }
1971         }
1972
1973         /*
1974          * Converts a <code>IResourceDelta</code> rooted in a <code>Workspace</code>
1975          * into the corresponding set of <code>IJavaElementDelta</code>, rooted
1976          * in the relevant <code>JavaModel</code>s.
1977          */
1978         private IJavaElementDelta processResourceDelta(IResourceDelta changes) {
1979
1980                 try {
1981                         IJavaModel model = this.manager.getJavaModel();
1982                         if (!model.isOpen()) {
1983                                 // force opening of java model so that java element delta are
1984                                 // reported
1985                                 try {
1986                                         model.open(null);
1987                                 } catch (JavaModelException e) {
1988                                         if (VERBOSE) {
1989                                                 e.printStackTrace();
1990                                         }
1991                                         return null;
1992                                 }
1993                         }
1994                         this.state.initializeRoots();
1995                         this.currentElement = null;
1996
1997                         // get the workspace delta, and start processing there.
1998                         IResourceDelta[] deltas = changes.getAffectedChildren();
1999                         for (int i = 0; i < deltas.length; i++) {
2000                                 IResourceDelta delta = deltas[i];
2001                                 IResource res = delta.getResource();
2002
2003                                 // find out the element type
2004                                 // RootInfo rootInfo = null;
2005                                 int elementType;
2006                                 IProject proj = (IProject) res;
2007                                 boolean wasJavaProject = this.manager.getJavaModel()
2008                                                 .findJavaProject(proj) != null;
2009                                 boolean isJavaProject = JavaProject.hasJavaNature(proj);
2010                                 if (!wasJavaProject && !isJavaProject) {
2011                                         elementType = NON_JAVA_RESOURCE;
2012                                 } else {
2013                                         // rootInfo = this.enclosingRootInfo(res.getFullPath(),
2014                                         // delta.getKind());
2015                                         // if (rootInfo != null &&
2016                                         // rootInfo.isRootOfProject(res.getFullPath())) {
2017                                         // elementType = IJavaElement.PACKAGE_FRAGMENT_ROOT;
2018                                         // } else {
2019                                         elementType = IJavaElement.JAVA_PROJECT;
2020                                         // }
2021                                 }
2022
2023                                 // traverse delta
2024                                 // this.traverseDelta(delta, elementType, rootInfo, null);
2025
2026                                 if (elementType == NON_JAVA_RESOURCE
2027                                                 || (wasJavaProject != isJavaProject && (delta.getKind()) == IResourceDelta.CHANGED)) { // project
2028                                                                                                                                                                                                                                 // has
2029                                                                                                                                                                                                                                 // changed
2030                                                                                                                                                                                                                                 // nature
2031                                                                                                                                                                                                                                 // (description
2032                                                                                                                                                                                                                                 // or
2033                                                                                                                                                                                                                                 // open/closed)
2034                                         try {
2035                                                 // add child as non java resource
2036                                                 nonJavaResourcesChanged((JavaModel) model, delta);
2037                                         } catch (JavaModelException e) {
2038                                                 // java model could not be opened
2039                                         }
2040                                 }
2041
2042                         }
2043                         // refreshPackageFragmentRoots();
2044                         // resetProjectCaches();
2045
2046                         return this.currentDelta;
2047                 } finally {
2048                         this.currentDelta = null;
2049                         // this.rootsToRefresh.clear();
2050                         // this.projectCachesToReset.clear();
2051                 }
2052         }
2053
2054         /*
2055          * Converts an <code>IResourceDelta</code> and its children into the
2056          * corresponding <code>IJavaElementDelta</code>s.
2057          */
2058         // private void traverseDelta(
2059         // IResourceDelta delta,
2060         // int elementType,
2061         // RootInfo rootInfo,
2062         // OutputsInfo outputsInfo) {
2063         //                      
2064         // IResource res = delta.getResource();
2065         //      
2066         // // set stack of elements
2067         // if (this.currentElement == null && rootInfo != null) {
2068         // // this.currentElement = rootInfo.project;
2069         // }
2070         //              
2071         // // process current delta
2072         // boolean processChildren = true;
2073         // if (res instanceof IProject) {
2074         // processChildren =
2075         // this.updateCurrentDeltaAndIndex(
2076         // delta,
2077         // elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT ?
2078         // IJavaElement.JAVA_PROJECT : // case of prj=src
2079         // elementType,
2080         // rootInfo);
2081         // } else if (rootInfo != null) {
2082         // processChildren = this.updateCurrentDeltaAndIndex(delta, elementType,
2083         // rootInfo);
2084         // } else {
2085         // // not yet inside a package fragment root
2086         // processChildren = true;
2087         // }
2088         //              
2089         // // get the project's output locations and traverse mode
2090         // if (outputsInfo == null) outputsInfo = this.outputsInfo(rootInfo, res);
2091         //      
2092         // // process children if needed
2093         // if (processChildren) {
2094         // IResourceDelta[] children = delta.getAffectedChildren();
2095         // boolean oneChildOnClasspath = false;
2096         // int length = children.length;
2097         // IResourceDelta[] orphanChildren = null;
2098         // Openable parent = null;
2099         // boolean isValidParent = true;
2100         // for (int i = 0; i < length; i++) {
2101         // IResourceDelta child = children[i];
2102         // IResource childRes = child.getResource();
2103         //      
2104         // // check source attachment change
2105         // this.checkSourceAttachmentChange(child, childRes);
2106         //                              
2107         // // find out whether the child is a package fragment root of the current
2108         // project
2109         // IPath childPath = childRes.getFullPath();
2110         // int childKind = child.getKind();
2111         // RootInfo childRootInfo = this.rootInfo(childPath, childKind);
2112         // if (childRootInfo != null && !childRootInfo.isRootOfProject(childPath)) {
2113         // // package fragment root of another project (dealt with later)
2114         // childRootInfo = null;
2115         // }
2116         //                              
2117         // // compute child type
2118         // int childType =
2119         // this.elementType(
2120         // childRes,
2121         // childKind,
2122         // elementType,
2123         // rootInfo == null ? childRootInfo : rootInfo
2124         // );
2125         //                                              
2126         // // is childRes in the output folder and is it filtered out ?
2127         // boolean isResFilteredFromOutput =
2128         // this.isResFilteredFromOutput(outputsInfo, childRes, childType);
2129         //
2130         // boolean isNestedRoot = rootInfo != null && childRootInfo != null;
2131         // if (!isResFilteredFromOutput
2132         // && !isNestedRoot) { // do not treat as non-java rsc if nested root
2133         //
2134         // this.traverseDelta(child, childType, rootInfo == null ? childRootInfo :
2135         // rootInfo, outputsInfo); // traverse delta for child in the same project
2136         //
2137         // if (childType == NON_JAVA_RESOURCE) {
2138         // if (rootInfo != null) { // if inside a package fragment root
2139         // if (!isValidParent) continue;
2140         // if (parent == null) {
2141         // // find the parent of the non-java resource to attach to
2142         // if (this.currentElement == null
2143         // || !rootInfo.project.equals(this.currentElement.getJavaProject())) { //
2144         // note if currentElement is the IJavaModel, getJavaProject() is null
2145         // // force the currentProject to be used
2146         // this.currentElement = rootInfo.project;
2147         // }
2148         // if (elementType == IJavaElement.JAVA_PROJECT
2149         // || (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT
2150         // && res instanceof IProject)) {
2151         // // NB: attach non-java resource to project (not to its package fragment
2152         // root)
2153         // parent = rootInfo.project;
2154         // } else {
2155         // parent = this.createElement(res, elementType, rootInfo);
2156         // }
2157         // if (parent == null) {
2158         // isValidParent = false;
2159         // continue;
2160         // }
2161         // }
2162         // // add child as non java resource
2163         // try {
2164         // nonJavaResourcesChanged(parent, child);
2165         // } catch (JavaModelException e) {
2166         // // ignore
2167         // }
2168         // } else {
2169         // // the non-java resource (or its parent folder) will be attached to the
2170         // java project
2171         // if (orphanChildren == null) orphanChildren = new IResourceDelta[length];
2172         // orphanChildren[i] = child;
2173         // }
2174         // } else {
2175         // oneChildOnClasspath = true;
2176         // }
2177         // } else {
2178         // oneChildOnClasspath = true; // to avoid reporting child delta as non-java
2179         // resource delta
2180         // }
2181         //                                                              
2182         // // if child is a nested root
2183         // // or if it is not a package fragment root of the current project
2184         // // but it is a package fragment root of another project, traverse delta
2185         // too
2186         // if (isNestedRoot
2187         // || (childRootInfo == null && (childRootInfo = this.rootInfo(childPath,
2188         // childKind)) != null)) {
2189         // this.traverseDelta(child, IJavaElement.PACKAGE_FRAGMENT_ROOT,
2190         // childRootInfo, null); // binary output of childRootInfo.project cannot be
2191         // this root
2192         // }
2193         //      
2194         // // if the child is a package fragment root of one or several other
2195         // projects
2196         // ArrayList rootList;
2197         // if ((rootList = this.otherRootsInfo(childPath, childKind)) != null) {
2198         // Iterator iterator = rootList.iterator();
2199         // while (iterator.hasNext()) {
2200         // childRootInfo = (RootInfo) iterator.next();
2201         // this.traverseDelta(child, IJavaElement.PACKAGE_FRAGMENT_ROOT,
2202         // childRootInfo, null); // binary output of childRootInfo.project cannot be
2203         // this root
2204         // }
2205         // }
2206         // }
2207         // if (orphanChildren != null
2208         // && (oneChildOnClasspath // orphan children are siblings of a package
2209         // fragment root
2210         // || res instanceof IProject)) { // non-java resource directly under a
2211         // project
2212         //                                              
2213         // // attach orphan children
2214         // IProject rscProject = res.getProject();
2215         // JavaProject adoptiveProject = (JavaProject)JavaCore.create(rscProject);
2216         // if (adoptiveProject != null
2217         // && JavaProject.hasJavaNature(rscProject)) { // delta iff Java project
2218         // (18698)
2219         // for (int i = 0; i < length; i++) {
2220         // if (orphanChildren[i] != null) {
2221         // try {
2222         // nonJavaResourcesChanged(adoptiveProject, orphanChildren[i]);
2223         // } catch (JavaModelException e) {
2224         // // ignore
2225         // }
2226         // }
2227         // }
2228         // }
2229         // } // else resource delta will be added by parent
2230         // } // else resource delta will be added by parent
2231         // }
2232         private void notifyListeners(IJavaElementDelta deltaToNotify,
2233                         int eventType, IElementChangedListener[] listeners,
2234                         int[] listenerMask, int listenerCount) {
2235                 final ElementChangedEvent extraEvent = new ElementChangedEvent(
2236                                 deltaToNotify, eventType);
2237                 for (int i = 0; i < listenerCount; i++) {
2238                         if ((listenerMask[i] & eventType) != 0) {
2239                                 final IElementChangedListener listener = listeners[i];
2240                                 long start = -1;
2241                                 if (VERBOSE) {
2242                                         System.out
2243                                                         .print("Listener #" + (i + 1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$
2244                                         start = System.currentTimeMillis();
2245                                 }
2246                                 // wrap callbacks with Safe runnable for subsequent listeners to
2247                                 // be called when some are causing grief
2248                                 Platform.run(new ISafeRunnable() {
2249                                         public void handleException(Throwable exception) {
2250                                                 Util
2251                                                                 .log(exception,
2252                                                                                 "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
2253                                         }
2254
2255                                         public void run() throws Exception {
2256                                                 listener.elementChanged(extraEvent);
2257                                         }
2258                                 });
2259                                 if (VERBOSE) {
2260                                         System.out
2261                                                         .println(" -> " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
2262                                 }
2263                         }
2264                 }
2265         }
2266
2267         // private void notifyTypeHierarchies(IElementChangedListener[] listeners,
2268         // int listenerCount) {
2269         // for (int i= 0; i < listenerCount; i++) {
2270         // final IElementChangedListener listener = listeners[i];
2271         // if (!(listener instanceof TypeHierarchy)) continue;
2272         //
2273         // // wrap callbacks with Safe runnable for subsequent listeners to be
2274         // called when some are causing grief
2275         // Platform.run(new ISafeRunnable() {
2276         // public void handleException(Throwable exception) {
2277         // ProjectPrefUtil.log(exception, "Exception occurred in listener of Java
2278         // element change notification"); //$NON-NLS-1$
2279         // }
2280         // public void run() throws Exception {
2281         // TypeHierarchy typeHierarchy = (TypeHierarchy)listener;
2282         // if (typeHierarchy.hasFineGrainChanges()) {
2283         // // case of changes in primary working copies
2284         // typeHierarchy.needsRefresh = true;
2285         // typeHierarchy.fireChange();
2286         // }
2287         // }
2288         // });
2289         // }
2290         // }
2291         /*
2292          * Generic processing for elements with changed contents:<ul> <li>The
2293          * element is closed such that any subsequent accesses will re-open the
2294          * element reflecting its new structure. <li>An entry is made in the delta
2295          * reporting a content change (K_CHANGE with F_CONTENT flag set). </ul>
2296          */
2297         private void nonJavaResourcesChanged(Openable element, IResourceDelta delta)
2298                         throws JavaModelException {
2299
2300                 // reset non-java resources if element was open
2301                 if (element.isOpen()) {
2302                         JavaElementInfo info = (JavaElementInfo) element.getElementInfo();
2303                         switch (element.getElementType()) {
2304                         case IJavaElement.JAVA_MODEL:
2305                                 ((JavaModelInfo) info).nonJavaResources = null;
2306                                 currentDelta().addResourceDelta(delta);
2307                                 return;
2308                         case IJavaElement.JAVA_PROJECT:
2309                                 ((JavaProjectElementInfo) info).setNonJavaResources(null);
2310
2311                                 // if a package fragment root is the project, clear it too
2312                                 JavaProject project = (JavaProject) element;
2313                                 PackageFragmentRoot projectRoot = (PackageFragmentRoot) project
2314                                                 .getPackageFragmentRoot(project.getProject());
2315                                 if (projectRoot.isOpen()) {
2316                                         ((PackageFragmentRootInfo) projectRoot.getElementInfo())
2317                                                         .setNonJavaResources(null);
2318                                 }
2319                                 break;
2320                         case IJavaElement.PACKAGE_FRAGMENT:
2321                                 ((PackageFragmentInfo) info).setNonJavaResources(null);
2322                                 break;
2323                         case IJavaElement.PACKAGE_FRAGMENT_ROOT:
2324                                 ((PackageFragmentRootInfo) info).setNonJavaResources(null);
2325                         }
2326                 }
2327
2328                 JavaElementDelta current = currentDelta();
2329                 JavaElementDelta elementDelta = current.find(element);
2330                 if (elementDelta == null) {
2331                         // don't use find after creating the delta as it can be null (see
2332                         // https://bugs.eclipse.org/bugs/show_bug.cgi?id=63434)
2333                         elementDelta = current
2334                                         .changed(element, IJavaElementDelta.F_CONTENT);
2335                 }
2336                 elementDelta.addResourceDelta(delta);
2337         }
2338
2339         /*
2340          * Flushes all deltas without firing them.
2341          */
2342         public void flush() {
2343                 this.javaModelDeltas = new ArrayList();
2344         }
2345
2346         /*
2347          * Finds the root info this path is included in. Returns null if not found.
2348          */
2349         RootInfo enclosingRootInfo(IPath path, int kind) {
2350                 while (path != null && path.segmentCount() > 0) {
2351                         RootInfo rootInfo = this.rootInfo(path, kind);
2352                         if (rootInfo != null)
2353                                 return rootInfo;
2354                         path = path.removeLastSegments(1);
2355                 }
2356                 return null;
2357         }
2358
2359         /*
2360          * Fire Java Model delta, flushing them after the fact after post_change
2361          * notification. If the firing mode has been turned off, this has no effect.
2362          */
2363         public void fire(IJavaElementDelta customDelta, int eventType) {
2364                 if (!this.isFiring)
2365                         return;
2366
2367                 if (DEBUG) {
2368                         System.out
2369                                         .println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$
2370                 }
2371
2372                 IJavaElementDelta deltaToNotify;
2373                 if (customDelta == null) {
2374                         deltaToNotify = this.mergeDeltas(this.javaModelDeltas);
2375                 } else {
2376                         deltaToNotify = customDelta;
2377                 }
2378
2379                 // Refresh internal scopes
2380                 // if (deltaToNotify != null) {
2381                 // Iterator scopes = this.manager.searchScopes.keySet().iterator();
2382                 // while (scopes.hasNext()) {
2383                 // AbstractSearchScope scope = (AbstractSearchScope)scopes.next();
2384                 // scope.processDelta(deltaToNotify);
2385                 // }
2386                 // }
2387
2388                 // Notification
2389
2390                 // Important: if any listener reacts to notification by updating the
2391                 // listeners list or mask, these lists will
2392                 // be duplicated, so it is necessary to remember original lists in a
2393                 // variable (since field values may change under us)
2394                 IElementChangedListener[] listeners = this.state.elementChangedListeners;
2395                 int[] listenerMask = this.state.elementChangedListenerMasks;
2396                 int listenerCount = this.state.elementChangedListenerCount;
2397
2398                 switch (eventType) {
2399                 case DEFAULT_CHANGE_EVENT:
2400                         firePostChangeDelta(deltaToNotify, listeners, listenerMask,
2401                                         listenerCount);
2402                         fireReconcileDelta(listeners, listenerMask, listenerCount);
2403                         break;
2404                 case ElementChangedEvent.POST_CHANGE:
2405                         firePostChangeDelta(deltaToNotify, listeners, listenerMask,
2406                                         listenerCount);
2407                         fireReconcileDelta(listeners, listenerMask, listenerCount);
2408                         break;
2409                 }
2410         }
2411
2412         private void firePostChangeDelta(IJavaElementDelta deltaToNotify,
2413                         IElementChangedListener[] listeners, int[] listenerMask,
2414                         int listenerCount) {
2415
2416                 // post change deltas
2417                 if (DEBUG) {
2418                         System.out
2419                                         .println("FIRING POST_CHANGE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
2420                         System.out
2421                                         .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
2422                 }
2423                 if (deltaToNotify != null) {
2424                         // flush now so as to keep listener reactions to post their own
2425                         // deltas for subsequent iteration
2426                         this.flush();
2427
2428                         notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE,
2429                                         listeners, listenerMask, listenerCount);
2430                 }
2431         }
2432
2433         private void fireReconcileDelta(IElementChangedListener[] listeners,
2434                         int[] listenerMask, int listenerCount) {
2435
2436                 IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas
2437                                 .values());
2438                 if (DEBUG) {
2439                         System.out
2440                                         .println("FIRING POST_RECONCILE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
2441                         System.out
2442                                         .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
2443                 }
2444                 if (deltaToNotify != null) {
2445                         // flush now so as to keep listener reactions to post their own
2446                         // deltas for subsequent iteration
2447                         this.reconcileDeltas = new HashMap();
2448
2449                         notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE,
2450                                         listeners, listenerMask, listenerCount);
2451                 }
2452         }
2453
2454         /*
2455          * Returns the root info for the given path. Look in the old roots table if
2456          * kind is REMOVED.
2457          */
2458         RootInfo rootInfo(IPath path, int kind) {
2459                 if (kind == IResourceDelta.REMOVED) {
2460                         return (RootInfo) this.oldRoots.get(path);
2461                 } else {
2462                         return (RootInfo) this.roots.get(path);
2463                 }
2464         }
2465
2466         /*
2467          * Returns the other root infos for the given path. Look in the old other
2468          * roots table if kind is REMOVED.
2469          */
2470         ArrayList otherRootsInfo(IPath path, int kind) {
2471                 if (kind == IResourceDelta.REMOVED) {
2472                         return (ArrayList) this.oldOtherRoots.get(path);
2473                 } else {
2474                         return (ArrayList) this.otherRoots.get(path);
2475                 }
2476         }
2477
2478         /**
2479          * Converts an <code>IResourceDelta</code> and its children into the
2480          * corresponding <code>IJavaElementDelta</code>s. Return whether the
2481          * delta corresponds to a java element. If it is not a java element, it will
2482          * be added as a non-java resource by the sender of this method.
2483          */
2484         // protected boolean traverseDelta(
2485         // IResourceDelta delta,
2486         // int elementType,
2487         // RootInfo rootInfo,
2488         // OutputsInfo outputsInfo) {
2489         //                      
2490         // IResource res = delta.getResource();
2491         //      
2492         // // set stack of elements
2493         // if (this.currentElement == null && rootInfo != null) {
2494         // this.currentElement = (Openable)rootInfo.project;
2495         // }
2496         //              
2497         // // process current delta
2498         // boolean processChildren = true;
2499         // if (res instanceof IProject) {
2500         // processChildren =
2501         // this.updateCurrentDeltaAndIndex(
2502         // delta,
2503         // elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT ?
2504         // IJavaElement.JAVA_PROJECT : // case of prj=src
2505         // elementType,
2506         // rootInfo);
2507         // } else if (rootInfo != null) {
2508         // processChildren = this.updateCurrentDeltaAndIndex(delta, elementType,
2509         // rootInfo);
2510         // } else {
2511         // // not yet inside a package fragment root
2512         // processChildren = true;
2513         // }
2514         //              
2515         // // get the project's output locations and traverse mode
2516         // if (outputsInfo == null) outputsInfo = this.outputsInfo(rootInfo, res);
2517         //      
2518         // // process children if needed
2519         // if (processChildren) {
2520         // IResourceDelta[] children = delta.getAffectedChildren();
2521         // boolean oneChildOnClasspath = false;
2522         // int length = children.length;
2523         // IResourceDelta[] orphanChildren = null;
2524         // Openable parent = null;
2525         // boolean isValidParent = true;
2526         // for (int i = 0; i < length; i++) {
2527         // IResourceDelta child = children[i];
2528         // IResource childRes = child.getResource();
2529         //      
2530         // // check source attachment change
2531         // this.checkSourceAttachmentChange(child, childRes);
2532         //                              
2533         // // find out whether the child is a package fragment root of the current
2534         // project
2535         // IPath childPath = childRes.getFullPath();
2536         // int childKind = child.getKind();
2537         // RootInfo childRootInfo = this.rootInfo(childPath, childKind);
2538         // if (childRootInfo != null && !childRootInfo.isRootOfProject(childPath)) {
2539         // // package fragment root of another project (dealt with later)
2540         // childRootInfo = null;
2541         // }
2542         //                              
2543         // // compute child type
2544         // int childType =
2545         // this.elementType(
2546         // childRes,
2547         // childKind,
2548         // elementType,
2549         // rootInfo == null ? childRootInfo : rootInfo
2550         // );
2551         //                                              
2552         // // is childRes in the output folder and is it filtered out ?
2553         // boolean isResFilteredFromOutput =
2554         // this.isResFilteredFromOutput(outputsInfo, childRes, childType);
2555         //
2556         // boolean isNestedRoot = rootInfo != null && childRootInfo != null;
2557         // if (!isResFilteredFromOutput
2558         // && !isNestedRoot) { // do not treat as non-java rsc if nested root
2559         // if (!this.traverseDelta(child, childType, rootInfo == null ?
2560         // childRootInfo : rootInfo, outputsInfo)) { // traverse delta for child in
2561         // the same project
2562         // // it is a non-java resource
2563         // try {
2564         // if (rootInfo != null) { // if inside a package fragment root
2565         // if (!isValidParent) continue;
2566         // if (parent == null) {
2567         // // find the parent of the non-java resource to attach to
2568         // if (this.currentElement == null
2569         // || !this.currentElement.getJavaProject().equals(rootInfo.project)) {
2570         // // force the currentProject to be used
2571         // this.currentElement = (Openable)rootInfo.project;
2572         // }
2573         // if (elementType == IJavaElement.JAVA_PROJECT
2574         // || (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT
2575         // && res instanceof IProject)) {
2576         // // NB: attach non-java resource to project (not to its package fragment
2577         // root)
2578         // parent = (Openable)rootInfo.project;
2579         // } else {
2580         // parent = this.createElement(res, elementType, rootInfo);
2581         // }
2582         // if (parent == null) {
2583         // isValidParent = false;
2584         // continue;
2585         // }
2586         // }
2587         // // add child as non java resource
2588         // nonJavaResourcesChanged(parent, child);
2589         // } else {
2590         // // the non-java resource (or its parent folder) will be attached to the
2591         // java project
2592         // if (orphanChildren == null) orphanChildren = new IResourceDelta[length];
2593         // orphanChildren[i] = child;
2594         // }
2595         // } catch (JavaModelException e) {
2596         // }
2597         // } else {
2598         // oneChildOnClasspath = true;
2599         // }
2600         // } else {
2601         // oneChildOnClasspath = true; // to avoid reporting child delta as non-java
2602         // resource delta
2603         // }
2604         //                                                              
2605         // // if child is a nested root
2606         // // or if it is not a package fragment root of the current project
2607         // // but it is a package fragment root of another project, traverse delta
2608         // too
2609         // if (isNestedRoot
2610         // || (childRootInfo == null && (childRootInfo = this.rootInfo(childPath,
2611         // childKind)) != null)) {
2612         // this.traverseDelta(child, IJavaElement.PACKAGE_FRAGMENT_ROOT,
2613         // childRootInfo, null); // binary output of childRootInfo.project cannot be
2614         // this root
2615         // // NB: No need to check the return value as the child can only be on the
2616         // classpath
2617         // }
2618         //      
2619         // // if the child is a package fragment root of one or several other
2620         // projects
2621         // ArrayList rootList;
2622         // if ((rootList = this.otherRootsInfo(childPath, childKind)) != null) {
2623         // Iterator iterator = rootList.iterator();
2624         // while (iterator.hasNext()) {
2625         // childRootInfo = (RootInfo) iterator.next();
2626         // this.traverseDelta(child, IJavaElement.PACKAGE_FRAGMENT_ROOT,
2627         // childRootInfo, null); // binary output of childRootInfo.project cannot be
2628         // this root
2629         // }
2630         // }
2631         // }
2632         // if (orphanChildren != null
2633         // && (oneChildOnClasspath // orphan children are siblings of a package
2634         // fragment root
2635         // || res instanceof IProject)) { // non-java resource directly under a
2636         // project
2637         //                                              
2638         // // attach orphan children
2639         // IProject rscProject = res.getProject();
2640         // JavaProject adoptiveProject = (JavaProject)JavaCore.create(rscProject);
2641         // if (adoptiveProject != null
2642         // && JavaProject.hasJavaNature(rscProject)) { // delta iff Java project
2643         // (18698)
2644         // for (int i = 0; i < length; i++) {
2645         // if (orphanChildren[i] != null) {
2646         // try {
2647         // nonJavaResourcesChanged(adoptiveProject, orphanChildren[i]);
2648         // } catch (JavaModelException e) {
2649         // }
2650         // }
2651         // }
2652         // }
2653         // } // else resource delta will be added by parent
2654         // return elementType != NON_JAVA_RESOURCE; // TODO: (jerome) do we still
2655         // need to return? (check could be done by caller)
2656         // } else {
2657         // return elementType != NON_JAVA_RESOURCE;
2658         // }
2659         // }
2660         /**
2661          * Update the classpath markers and cycle markers for the projects to
2662          * update.
2663          */
2664         // void updateClasspathMarkers() {
2665         // try {
2666         // if (!ResourcesPlugin.getWorkspace().isAutoBuilding()) {
2667         // Iterator iterator = this.projectsToUpdate.iterator();
2668         // while (iterator.hasNext()) {
2669         // try {
2670         // JavaProject project = (JavaProject)iterator.next();
2671         //                                              
2672         // // force classpath marker refresh
2673         // project.getResolvedClasspath(
2674         // true, // ignoreUnresolvedEntry
2675         // true); // generateMarkerOnError
2676         //                                              
2677         // } catch (JavaModelException e) {
2678         // }
2679         // }
2680         // }
2681         // if (!this.projectsToUpdate.isEmpty()){
2682         // try {
2683         // // update all cycle markers
2684         // JavaProject.updateAllCycleMarkers();
2685         // } catch (JavaModelException e) {
2686         // }
2687         // }
2688         // } finally {
2689         // this.projectsToUpdate = new HashSet();
2690         // }
2691         // }
2692         /*
2693          * Update the current delta (ie. add/remove/change the given element) and
2694          * update the correponding index. Returns whether the children of the given
2695          * delta must be processed. @throws a JavaModelException if the delta
2696          * doesn't correspond to a java element of the given type.
2697          */
2698         // private boolean updateCurrentDeltaAndIndex(IResourceDelta delta, int
2699         // elementType, RootInfo rootInfo) {
2700         // Openable element;
2701         // switch (delta.getKind()) {
2702         // case IResourceDelta.ADDED :
2703         // IResource deltaRes = delta.getResource();
2704         // element = this.createElement(deltaRes, elementType, rootInfo);
2705         // if (element == null) {
2706         // // resource might be containing shared roots (see bug 19058)
2707         // this.updateRoots(deltaRes.getFullPath(), delta);
2708         // return false;
2709         // }
2710         // this.updateIndex(element, delta);
2711         // this.elementAdded(element, delta, rootInfo);
2712         // return false;
2713         // case IResourceDelta.REMOVED :
2714         // deltaRes = delta.getResource();
2715         // element = this.createElement(deltaRes, elementType, rootInfo);
2716         // if (element == null) {
2717         // // resource might be containing shared roots (see bug 19058)
2718         // this.updateRoots(deltaRes.getFullPath(), delta);
2719         // return false;
2720         // }
2721         // this.updateIndex(element, delta);
2722         // this.elementRemoved(element, delta, rootInfo);
2723         //      
2724         // if (deltaRes.getType() == IResource.PROJECT){
2725         // // reset the corresponding project built state, since cannot reuse if
2726         // added back
2727         // this.manager.setLastBuiltState((IProject)deltaRes, null /*no state*/);
2728         // }
2729         // return false;
2730         // case IResourceDelta.CHANGED :
2731         // int flags = delta.getFlags();
2732         // if ((flags & IResourceDelta.CONTENT) != 0) {
2733         // // content has changed
2734         // element = this.createElement(delta.getResource(), elementType, rootInfo);
2735         // if (element == null) return false;
2736         // this.updateIndex(element, delta);
2737         // this.contentChanged(element, delta);
2738         // } else if (elementType == IJavaElement.JAVA_PROJECT) {
2739         // if ((flags & IResourceDelta.OPEN) != 0) {
2740         // // project has been opened or closed
2741         // IProject res = (IProject)delta.getResource();
2742         // element = this.createElement(res, elementType, rootInfo);
2743         // if (element == null) {
2744         // // resource might be containing shared roots (see bug 19058)
2745         // this.updateRoots(res.getFullPath(), delta);
2746         // return false;
2747         // }
2748         // if (res.isOpen()) {
2749         // if (JavaProject.hasJavaNature(res)) {
2750         // this.elementAdded(element, delta, rootInfo);
2751         // this.indexManager.indexAll(res);
2752         // }
2753         // } else {
2754         // JavaModel javaModel = this.manager.getJavaModel();
2755         // boolean wasJavaProject = javaModel.findJavaProject(res) != null;
2756         // if (wasJavaProject) {
2757         // this.elementRemoved(element, delta, rootInfo);
2758         // this.indexManager.discardJobs(element.getElementName());
2759         // this.indexManager.removeIndexFamily(res.getFullPath());
2760         //                                                              
2761         // }
2762         // }
2763         // return false; // when a project is open/closed don't process children
2764         // }
2765         // if ((flags & IResourceDelta.DESCRIPTION) != 0) {
2766         // IProject res = (IProject)delta.getResource();
2767         // JavaModel javaModel = this.manager.getJavaModel();
2768         // boolean wasJavaProject = javaModel.findJavaProject(res) != null;
2769         // boolean isJavaProject = JavaProject.hasJavaNature(res);
2770         // if (wasJavaProject != isJavaProject) {
2771         // // project's nature has been added or removed
2772         // element = this.createElement(res, elementType, rootInfo);
2773         // if (element == null) return false; // note its resources are still
2774         // visible as roots to other projects
2775         // if (isJavaProject) {
2776         // this.elementAdded(element, delta, rootInfo);
2777         // this.indexManager.indexAll(res);
2778         // } else {
2779         // this.elementRemoved(element, delta, rootInfo);
2780         // this.indexManager.discardJobs(element.getElementName());
2781         // this.indexManager.removeIndexFamily(res.getFullPath());
2782         // // reset the corresponding project built state, since cannot reuse if
2783         // added back
2784         // this.manager.setLastBuiltState(res, null /*no state*/);
2785         // }
2786         // return false; // when a project's nature is added/removed don't process
2787         // children
2788         // }
2789         // }
2790         // }
2791         // return true;
2792         // }
2793         // return true;
2794         // }
2795         /**
2796          * Traverse the set of projects which have changed namespace, and refresh
2797          * their dependents
2798          */
2799         // public void updateDependentNamelookups() {
2800         // Iterator iterator;
2801         // // update namelookup of dependent projects
2802         // iterator = this.projectsForDependentNamelookupRefresh.iterator();
2803         // HashSet affectedDependents = new HashSet();
2804         // while (iterator.hasNext()) {
2805         // JavaProject project = (JavaProject)iterator.next();
2806         // addDependentProjects(project.getPath(), affectedDependents);
2807         // }
2808         // iterator = affectedDependents.iterator();
2809         // while (iterator.hasNext()) {
2810         // JavaProject project = (JavaProject) iterator.next();
2811         // if (project.isOpen()){
2812         // try {
2813         // ((JavaProjectElementInfo)project.getElementInfo()).setNameLookup(null);
2814         // } catch (JavaModelException e) {
2815         // }
2816         // }
2817         // }
2818         // }
2819         // protected void updateIndex(Openable element, IResourceDelta delta) {
2820         //
2821         // if (indexManager == null)
2822         // return;
2823         //
2824         // switch (element.getElementType()) {
2825         // case IJavaElement.JAVA_PROJECT :
2826         // switch (delta.getKind()) {
2827         // case IResourceDelta.ADDED :
2828         // this.indexManager.indexAll(element.getJavaProject().getProject());
2829         // break;
2830         // case IResourceDelta.REMOVED :
2831         // this.indexManager.removeIndexFamily(element.getJavaProject().getProject().getFullPath());
2832         // // NB: Discarding index jobs belonging to this project was done during
2833         // PRE_DELETE
2834         // break;
2835         // // NB: Update of index if project is opened, closed, or its java nature
2836         // is added or removed
2837         // // is done in updateCurrentDeltaAndIndex
2838         // }
2839         // break;
2840         // case IJavaElement.PACKAGE_FRAGMENT_ROOT :
2841         // if (element instanceof JarPackageFragmentRoot) {
2842         // JarPackageFragmentRoot root = (JarPackageFragmentRoot)element;
2843         // // index jar file only once (if the root is in its declaring project)
2844         // IPath jarPath = root.getPath();
2845         // switch (delta.getKind()) {
2846         // case IResourceDelta.ADDED:
2847         // // index the new jar
2848         // indexManager.indexLibrary(jarPath, root.getJavaProject().getProject());
2849         // break;
2850         // case IResourceDelta.CHANGED:
2851         // // first remove the index so that it is forced to be re-indexed
2852         // indexManager.removeIndex(jarPath);
2853         // // then index the jar
2854         // indexManager.indexLibrary(jarPath, root.getJavaProject().getProject());
2855         // break;
2856         // case IResourceDelta.REMOVED:
2857         // // the jar was physically removed: remove the index
2858         // this.indexManager.discardJobs(jarPath.toString());
2859         // this.indexManager.removeIndex(jarPath);
2860         // break;
2861         // }
2862         // break;
2863         // } else {
2864         // int kind = delta.getKind();
2865         // if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
2866         // IPackageFragmentRoot root = (IPackageFragmentRoot)element;
2867         // this.updateRootIndex(root, root.getPackageFragment(""), delta);
2868         // //$NON-NLS-1$
2869         // break;
2870         // }
2871         // }
2872         // // don't break as packages of the package fragment root can be indexed
2873         // below
2874         // case IJavaElement.PACKAGE_FRAGMENT :
2875         // switch (delta.getKind()) {
2876         // case IResourceDelta.ADDED:
2877         // case IResourceDelta.REMOVED:
2878         // IPackageFragment pkg = null;
2879         // if (element instanceof IPackageFragmentRoot) {
2880         // IPackageFragmentRoot root = (IPackageFragmentRoot)element;
2881         // pkg = root.getPackageFragment(""); //$NON-NLS-1$
2882         // } else {
2883         // pkg = (IPackageFragment)element;
2884         // }
2885         // IResourceDelta[] children = delta.getAffectedChildren();
2886         // for (int i = 0, length = children.length; i < length; i++) {
2887         // IResourceDelta child = children[i];
2888         // IResource resource = child.getResource();
2889         // if (resource instanceof IFile) {
2890         // String name = resource.getName();
2891         // if (ProjectPrefUtil.isJavaFileName(name)) {
2892         // Openable cu = (Openable)pkg.getCompilationUnit(name);
2893         // this.updateIndex(cu, child);
2894         // } else if (ProjectPrefUtil.isClassFileName(name)) {
2895         // Openable classFile = (Openable)pkg.getClassFile(name);
2896         // this.updateIndex(classFile, child);
2897         // }
2898         // }
2899         // }
2900         // break;
2901         // }
2902         // break;
2903         // case IJavaElement.CLASS_FILE :
2904         // IFile file = (IFile) delta.getResource();
2905         // IJavaProject project = element.getJavaProject();
2906         // IPath binaryFolderPath = element.getPackageFragmentRoot().getPath();
2907         // // if the class file is part of the binary output, it has been created by
2908         // // the java builder -> ignore
2909         // try {
2910         // if (binaryFolderPath.equals(project.getOutputLocation())) {
2911         // break;
2912         // }
2913         // } catch (JavaModelException e) {
2914         // }
2915         // switch (delta.getKind()) {
2916         // case IResourceDelta.CHANGED :
2917         // // no need to index if the content has not changed
2918         // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0)
2919         // break;
2920         // case IResourceDelta.ADDED :
2921         // indexManager.addBinary(file, binaryFolderPath);
2922         // break;
2923         // case IResourceDelta.REMOVED :
2924         // indexManager.remove(file.getFullPath().toString(), binaryFolderPath);
2925         // break;
2926         // }
2927         // break;
2928         // case IJavaElement.COMPILATION_UNIT :
2929         // file = (IFile) delta.getResource();
2930         // switch (delta.getKind()) {
2931         // case IResourceDelta.CHANGED :
2932         // // no need to index if the content has not changed
2933         // if ((delta.getFlags() & IResourceDelta.CONTENT) == 0)
2934         // break;
2935         // case IResourceDelta.ADDED :
2936         // indexManager.addSource(file,
2937         // file.getProject().getProject().getFullPath());
2938         // break;
2939         // case IResourceDelta.REMOVED :
2940         // indexManager.remove(file.getFullPath().toString(),
2941         // file.getProject().getProject().getFullPath());
2942         // break;
2943         // }
2944         // }
2945         // }
2946         /**
2947          * Upadtes the index of the given root (assuming it's an addition or a
2948          * removal). This is done recusively, pkg being the current package.
2949          */
2950         // private void updateRootIndex(IPackageFragmentRoot root, IPackageFragment
2951         // pkg, IResourceDelta delta) {
2952         // this.updateIndex((Openable)pkg, delta);
2953         // IResourceDelta[] children = delta.getAffectedChildren();
2954         // String name = pkg.getElementName();
2955         // for (int i = 0, length = children.length; i < length; i++) {
2956         // IResourceDelta child = children[i];
2957         // IResource resource = child.getResource();
2958         // if (resource instanceof IFolder) {
2959         // String subpkgName =
2960         // name.length() == 0 ?
2961         // resource.getName() :
2962         // name + "." + resource.getName(); //$NON-NLS-1$
2963         // IPackageFragment subpkg = root.getPackageFragment(subpkgName);
2964         // this.updateRootIndex(root, subpkg, child);
2965         // }
2966         // }
2967         // }
2968         /*
2969          * Update the roots that are affected by the addition or the removal of the
2970          * given container resource.
2971          */
2972         // private void updateRoots(IPath containerPath, IResourceDelta
2973         // containerDelta) {
2974         // Map roots;
2975         // Map otherRoots;
2976         // if (containerDelta.getKind() == IResourceDelta.REMOVED) {
2977         // roots = this.oldRoots;
2978         // otherRoots = this.oldOtherRoots;
2979         // } else {
2980         // roots = this.roots;
2981         // otherRoots = this.otherRoots;
2982         // }
2983         // Iterator iterator = roots.keySet().iterator();
2984         // while (iterator.hasNext()) {
2985         // IPath path = (IPath)iterator.next();
2986         // if (containerPath.isPrefixOf(path) && !containerPath.equals(path)) {
2987         // IResourceDelta rootDelta =
2988         // containerDelta.findMember(path.removeFirstSegments(1));
2989         // if (rootDelta == null) continue;
2990         // RootInfo rootInfo = (RootInfo)roots.get(path);
2991         //
2992         // if (!rootInfo.project.getPath().isPrefixOf(path)) { // only consider
2993         // roots that are not included in the container
2994         // this.updateCurrentDeltaAndIndex(rootDelta,
2995         // IJavaElement.PACKAGE_FRAGMENT_ROOT, rootInfo);
2996         // }
2997         //                      
2998         // ArrayList rootList = (ArrayList)otherRoots.get(path);
2999         // if (rootList != null) {
3000         // Iterator otherProjects = rootList.iterator();
3001         // while (otherProjects.hasNext()) {
3002         // rootInfo = (RootInfo)otherProjects.next();
3003         // if (!rootInfo.project.getPath().isPrefixOf(path)) { // only consider
3004         // roots that are not included in the container
3005         // this.updateCurrentDeltaAndIndex(rootDelta,
3006         // IJavaElement.PACKAGE_FRAGMENT_ROOT, rootInfo);
3007         // }
3008         // }
3009         // }
3010         // }
3011         // }
3012         // }
3013 }