Refactory: replaced internal copy of Assert class with org.eclipse.core.runtime.Assert
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaElement.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.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16
17 import net.sourceforge.phpdt.core.ICompilationUnit;
18 import net.sourceforge.phpdt.core.IJavaElement;
19 import net.sourceforge.phpdt.core.IJavaModel;
20 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
21 import net.sourceforge.phpdt.core.IJavaProject;
22 import net.sourceforge.phpdt.core.IMember;
23 import net.sourceforge.phpdt.core.IOpenable;
24 import net.sourceforge.phpdt.core.IParent;
25 import net.sourceforge.phpdt.core.ISourceRange;
26 import net.sourceforge.phpdt.core.ISourceReference;
27 import net.sourceforge.phpdt.core.JavaModelException;
28 import net.sourceforge.phpdt.core.WorkingCopyOwner;
29 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
30 import net.sourceforge.phpdt.core.jdom.IDOMNode;
31 import net.sourceforge.phpdt.internal.core.util.MementoTokenizer;
32 import net.sourceforge.phpdt.internal.core.util.Util;
33 //incastrix
34 //import net.sourceforge.phpdt.internal.corext.Assert;
35 import org.eclipse.core.runtime.Assert;
36
37 import org.eclipse.core.resources.IResource;
38 import org.eclipse.core.resources.IResourceStatus;
39 import org.eclipse.core.resources.ResourcesPlugin;
40 import org.eclipse.core.runtime.CoreException;
41 import org.eclipse.core.runtime.IAdaptable;
42 import org.eclipse.core.runtime.IPath;
43 import org.eclipse.core.runtime.IProgressMonitor;
44 import org.eclipse.core.runtime.Path;
45 import org.eclipse.core.runtime.PlatformObject;
46 import org.eclipse.core.runtime.jobs.ISchedulingRule;
47
48 /**
49  * Root of Java element handle hierarchy.
50  * 
51  * @see IJavaElement
52  */
53 public abstract class JavaElement extends PlatformObject implements
54                 IJavaElement {
55         public static final char JEM_ESCAPE = '\\';
56
57         public static final char JEM_JAVAPROJECT = '=';
58
59         public static final char JEM_PACKAGEFRAGMENTROOT = Path.SEPARATOR;
60
61         public static final char JEM_PACKAGEFRAGMENT = '<';
62
63         public static final char JEM_FIELD = '^';
64
65         public static final char JEM_METHOD = '~';
66
67         public static final char JEM_INITIALIZER = '|';
68
69         public static final char JEM_COMPILATIONUNIT = '{';
70
71         // public static final char JEM_CLASSFILE = '(';
72         public static final char JEM_TYPE = '[';
73
74         public static final char JEM_PACKAGEDECLARATION = '%';
75
76         public static final char JEM_IMPORTDECLARATION = '#';
77
78         public static final char JEM_COUNT = '!';
79
80         public static final char JEM_LOCALVARIABLE = '@';
81
82         /**
83          * A count to uniquely identify this element in the case that a duplicate
84          * named element exists. For example, if there are two fields in a
85          * compilation unit with the same name, the occurrence count is used to
86          * distinguish them. The occurrence count starts at 1 (thus the first
87          * occurrence is occurrence 1, not occurrence 0).
88          */
89         protected int occurrenceCount = 1;
90
91         /**
92          * This element's type - one of the constants defined in
93          * IJavaLanguageElementTypes.
94          */
95         // protected int fLEType = 0;
96         /**
97          * This element's parent, or <code>null</code> if this element does not
98          * have a parent.
99          */
100         protected JavaElement parent;
101
102         /**
103          * This element's name, or an empty <code>String</code> if this element
104          * does not have a name.
105          */
106         protected String name;
107
108         protected static final Object NO_INFO = new Object();
109
110         /**
111          * Constructs a handle for a java element with the given parent element and
112          * name.
113          * 
114          * @param parent
115          *            The parent of java element
116          * @param name
117          *            The name of java element
118          * 
119          * @exception IllegalArgumentException
120          *                if the type is not one of the valid Java element type
121          *                constants
122          * 
123          */
124         protected JavaElement(JavaElement parent, String name)
125                         throws IllegalArgumentException {
126                 this.parent = parent;
127                 this.name = name;
128         }
129
130         /**
131          * @see IOpenable
132          */
133         public void close() throws JavaModelException {
134                 JavaModelManager.getJavaModelManager().removeInfoAndChildren(this);
135         }
136
137         /**
138          * This element is being closed. Do any necessary cleanup.
139          */
140         protected abstract void closing(Object info) throws JavaModelException;
141
142         /*
143          * Returns a new element info for this element.
144          */
145         protected abstract Object createElementInfo();
146
147         /**
148          * Returns true if this handle represents the same Java element as the given
149          * handle. By default, two handles represent the same element if they are
150          * identical or if they represent the same type of element, have equal
151          * names, parents, and occurrence counts.
152          * 
153          * <p>
154          * If a subclass has other requirements for equality, this method must be
155          * overridden.
156          * 
157          * @see Object#equals
158          */
159         public boolean equals(Object o) {
160
161                 if (this == o)
162                         return true;
163
164                 // Java model parent is null
165                 if (this.parent == null)
166                         return super.equals(o);
167                 if (o instanceof JavaElement) {
168                         // assume instanceof check is done in subclass
169                         JavaElement other = (JavaElement) o;
170                         return this.occurrenceCount == other.occurrenceCount
171                                         && this.name.equals(other.name)
172                                         && this.parent.equals(other.parent);
173                 }
174                 return false;
175         }
176
177         /**
178          * Returns true if this <code>JavaElement</code> is equivalent to the
179          * given <code>IDOMNode</code>.
180          */
181         protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
182                 return false;
183         }
184
185         protected void escapeMementoName(StringBuffer buffer, String mementoName) {
186                 for (int i = 0, length = mementoName.length(); i < length; i++) {
187                         char character = mementoName.charAt(i);
188                         switch (character) {
189                         case JEM_ESCAPE:
190                         case JEM_COUNT:
191                         case JEM_JAVAPROJECT:
192                         case JEM_PACKAGEFRAGMENTROOT:
193                         case JEM_PACKAGEFRAGMENT:
194                         case JEM_FIELD:
195                         case JEM_METHOD:
196                         case JEM_INITIALIZER:
197                         case JEM_COMPILATIONUNIT:
198                                 // case JEM_CLASSFILE:
199                         case JEM_TYPE:
200                         case JEM_PACKAGEDECLARATION:
201                         case JEM_IMPORTDECLARATION:
202                         case JEM_LOCALVARIABLE:
203                                 buffer.append(JEM_ESCAPE);
204                         }
205                         buffer.append(character);
206                 }
207         }
208
209         /**
210          * @see IJavaElement
211          */
212         public boolean exists() {
213
214                 try {
215                         getElementInfo();
216                         return true;
217                 } catch (JavaModelException e) {
218                 }
219                 return false;
220         }
221
222         /**
223          * Returns the <code>IDOMNode</code> that corresponds to this
224          * <code>JavaElement</code> or <code>null</code> if there is no
225          * corresponding node.
226          */
227         public IDOMNode findNode(IDOMCompilationUnit dom) {
228                 int type = getElementType();
229                 if (type == IJavaElement.COMPILATION_UNIT || type == IJavaElement.FIELD
230                                 || type == IJavaElement.IMPORT_DECLARATION
231                                 || type == IJavaElement.INITIALIZER
232                                 || type == IJavaElement.METHOD
233                                 || type == IJavaElement.PACKAGE_DECLARATION
234                                 || type == IJavaElement.TYPE) {
235                         ArrayList path = new ArrayList();
236                         IJavaElement element = this;
237                         while (element != null
238                                         && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
239                                 if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
240                                         // the DOM does not have import containers, so skip them
241                                         path.add(0, element);
242                                 }
243                                 element = element.getParent();
244                         }
245                         if (path.size() == 0) {
246                                 try {
247                                         if (equalsDOMNode(dom)) {
248                                                 return dom;
249                                         } else {
250                                                 return null;
251                                         }
252                                 } catch (JavaModelException e) {
253                                         return null;
254                                 }
255                         }
256                         return ((JavaElement) path.get(0)).followPath(path, 0, dom
257                                         .getFirstChild());
258                 } else {
259                         return null;
260                 }
261         }
262
263         /**
264          */
265         protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
266
267                 try {
268                         if (equalsDOMNode(node)) {
269                                 if (position == (path.size() - 1)) {
270                                         return node;
271                                 } else {
272                                         if (node.getFirstChild() != null) {
273                                                 position++;
274                                                 return ((JavaElement) path.get(position)).followPath(
275                                                                 path, position, node.getFirstChild());
276                                         } else {
277                                                 return null;
278                                         }
279                                 }
280                         } else if (node.getNextNode() != null) {
281                                 return followPath(path, position, node.getNextNode());
282                         } else {
283                                 return null;
284                         }
285                 } catch (JavaModelException e) {
286                         return null;
287                 }
288
289         }
290
291         /**
292          * @see IJavaElement
293          */
294         public IJavaElement getAncestor(int ancestorType) {
295
296                 IJavaElement element = this;
297                 while (element != null) {
298                         if (element.getElementType() == ancestorType)
299                                 return element;
300                         element = element.getParent();
301                 }
302                 return null;
303         }
304
305         /**
306          * Generates the element infos for this element, its ancestors (if they are
307          * not opened) and its children (if it is an Openable). Puts the newly
308          * created element info in the given map.
309          */
310         protected abstract void generateInfos(Object info, HashMap newElements,
311                         IProgressMonitor pm) throws JavaModelException;
312
313         /**
314          * @see IParent
315          */
316         public IJavaElement[] getChildren() throws JavaModelException {
317                 return ((JavaElementInfo) getElementInfo()).getChildren();
318         }
319
320         /**
321          * Returns a collection of (immediate) children of this node of the
322          * specified type.
323          * 
324          * @param type -
325          *            one of constants defined by IJavaLanguageElementTypes
326          */
327         public ArrayList getChildrenOfType(int type) throws JavaModelException {
328                 IJavaElement[] children = getChildren();
329                 int size = children.length;
330                 ArrayList list = new ArrayList(size);
331                 for (int i = 0; i < size; ++i) {
332                         JavaElement elt = (JavaElement) children[i];
333                         if (elt.getElementType() == type) {
334                                 list.add(elt);
335                         }
336                 }
337                 return list;
338         }
339
340         /**
341          * @see IMember
342          */
343         // public IClassFile getClassFile() {
344         // return null;
345         // }
346         /**
347          * @see IMember
348          */
349         public ICompilationUnit getCompilationUnit() {
350                 return null;
351         }
352
353         /**
354          * Returns the info for this handle. If this element is not already open, it
355          * and all of its parents are opened. Does not return null. NOTE: BinaryType
356          * infos are NOT rooted under JavaElementInfo.
357          * 
358          * @exception JavaModelException
359          *                if the element is not present or not accessible
360          */
361         public Object getElementInfo() throws JavaModelException {
362                 return getElementInfo(null);
363         }
364
365         /**
366          * Returns the info for this handle. If this element is not already open, it
367          * and all of its parents are opened. Does not return null. NOTE: BinaryType
368          * infos are NOT rooted under JavaElementInfo.
369          * 
370          * @exception JavaModelException
371          *                if the element is not present or not accessible
372          */
373         public Object getElementInfo(IProgressMonitor monitor)
374                         throws JavaModelException {
375
376                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
377                 Object info = manager.getInfo(this);
378                 if (info != null)
379                         return info;
380                 return openWhenClosed(createElementInfo(), monitor);
381         }
382
383         /**
384          * @see IAdaptable
385          */
386         public String getElementName() {
387                 return name;
388         }
389
390         /*
391          * Creates a Java element handle from the given memento. The given token is
392          * the current delimiter indicating the type of the next token(s). The given
393          * working copy owner is used only for compilation unit handles.
394          */
395         public abstract IJavaElement getHandleFromMemento(String token,
396                         MementoTokenizer memento, WorkingCopyOwner owner);
397
398         /*
399          * Creates a Java element handle from the given memento. The given working
400          * copy owner is used only for compilation unit handles.
401          */
402         public IJavaElement getHandleFromMemento(MementoTokenizer memento,
403                         WorkingCopyOwner owner) {
404                 if (!memento.hasMoreTokens())
405                         return this;
406                 String token = memento.nextToken();
407                 return getHandleFromMemento(token, memento, owner);
408         }
409
410         /*
411          * Update the occurence count of the receiver and creates a Java element
412          * handle from the given memento. The given working copy owner is used only
413          * for compilation unit handles.
414          */
415         public IJavaElement getHandleUpdatingCountFromMemento(
416                         MementoTokenizer memento, WorkingCopyOwner owner) {
417                 this.occurrenceCount = Integer.parseInt(memento.nextToken());
418                 if (!memento.hasMoreTokens())
419                         return this;
420                 String token = memento.nextToken();
421                 return getHandleFromMemento(token, memento, owner);
422         }
423
424         /**
425          * @see IJavaElement
426          */
427         public String getHandleIdentifier() {
428                 return getHandleMemento();
429         }
430
431         /**
432          * @see JavaElement#getHandleMemento()
433          */
434         public String getHandleMemento() {
435                 StringBuffer buff = new StringBuffer(((JavaElement) getParent())
436                                 .getHandleMemento());
437                 buff.append(getHandleMementoDelimiter());
438                 escapeMementoName(buff, getElementName());
439                 if (this.occurrenceCount > 1) {
440                         buff.append(JEM_COUNT);
441                         buff.append(this.occurrenceCount);
442                 }
443                 return buff.toString();
444         }
445
446         /**
447          * Returns the <code>char</code> that marks the start of this handles
448          * contribution to a memento.
449          */
450
451         /**
452          * Returns the <code>char</code> that marks the start of this handles
453          * contribution to a memento.
454          */
455         protected abstract char getHandleMementoDelimiter();
456
457         /**
458          * @see IJavaElement
459          */
460         public IJavaModel getJavaModel() {
461                 IJavaElement current = this;
462                 do {
463                         if (current instanceof IJavaModel)
464                                 return (IJavaModel) current;
465                 } while ((current = current.getParent()) != null);
466                 return null;
467         }
468
469         /**
470          * @see IJavaElement
471          */
472         public IJavaProject getJavaProject() {
473                 IJavaElement current = this;
474                 do {
475                         if (current instanceof IJavaProject)
476                                 return (IJavaProject) current;
477                 } while ((current = current.getParent()) != null);
478                 return null;
479         }
480
481         /**
482          * Returns the occurrence count of the handle.
483          */
484         protected int getOccurrenceCount() {
485                 return occurrenceCount;
486         }
487
488         /*
489          * @see IJavaElement
490          */
491         public IOpenable getOpenable() {
492                 return this.getOpenableParent();
493         }
494
495         /**
496          * Return the first instance of IOpenable in the parent hierarchy of this
497          * element.
498          * 
499          * <p>
500          * Subclasses that are not IOpenable's must override this method.
501          */
502         public IOpenable getOpenableParent() {
503
504                 return (IOpenable) parent;
505         }
506
507         /**
508          * @see IJavaElement
509          */
510         public IJavaElement getParent() {
511                 return parent;
512         }
513
514         /*
515          * @see IJavaElement#getPrimaryElement()
516          */
517         public IJavaElement getPrimaryElement() {
518                 return getPrimaryElement(true);
519         }
520
521         /*
522          * Returns the primary element. If checkOwner, and the cu owner is primary,
523          * return this element.
524          */
525         public IJavaElement getPrimaryElement(boolean checkOwner) {
526                 return this;
527         }
528
529         /**
530          * Returns the element that is located at the given source position in this
531          * element. This is a helper method for
532          * <code>ICompilationUnit#getElementAt</code>, and only works on
533          * compilation units and types. The position given is known to be within
534          * this element's source range already, and if no finer grained element is
535          * found at the position, this element is returned.
536          */
537         protected IJavaElement getSourceElementAt(int position)
538                         throws JavaModelException {
539                 if (this instanceof ISourceReference) {
540                         IJavaElement[] children = getChildren();
541                         int i;
542                         for (i = 0; i < children.length; i++) {
543                                 IJavaElement aChild = children[i];
544
545                                 if (aChild instanceof SourceRefElement) {
546                                         SourceRefElement child = (SourceRefElement) children[i];
547                                         ISourceRange range = child.getSourceRange();
548                                         // if (child.name.equals("stopObject")||range==null ||
549                                         // range.getOffset()<=0) {
550                                         // System.out.println(child.name);
551                                         // }
552                                         if (position < range.getOffset() + range.getLength()
553                                                         && position >= range.getOffset()) {
554                                                 if (child instanceof IParent) {
555                                                         return child.getSourceElementAt(position);
556                                                 } else {
557                                                         return child;
558                                                 }
559                                         }
560                                 }
561                         }
562                 } else {
563                         // should not happen
564                         Assert.isTrue(false);
565                 }
566                 return this;
567         }
568
569         /**
570          * Returns the SourceMapper facility for this element, or <code>null</code>
571          * if this element does not have a SourceMapper.
572          */
573         // public SourceMapper getSourceMapper() {
574         // return ((JavaElement)getParent()).getSourceMapper();
575         // }
576         /*
577          * (non-Javadoc)
578          * 
579          * @see net.sourceforge.phpdt.core.IJavaElement#getSchedulingRule()
580          */
581         public ISchedulingRule getSchedulingRule() {
582                 IResource resource = getResource();
583                 if (resource == null) {
584                         class NoResourceSchedulingRule implements ISchedulingRule {
585                                 public IPath path;
586
587                                 public NoResourceSchedulingRule(IPath path) {
588                                         this.path = path;
589                                 }
590
591                                 public boolean contains(ISchedulingRule rule) {
592                                         if (rule instanceof NoResourceSchedulingRule) {
593                                                 return this.path
594                                                                 .isPrefixOf(((NoResourceSchedulingRule) rule).path);
595                                         } else {
596                                                 return false;
597                                         }
598                                 }
599
600                                 public boolean isConflicting(ISchedulingRule rule) {
601                                         if (rule instanceof NoResourceSchedulingRule) {
602                                                 IPath otherPath = ((NoResourceSchedulingRule) rule).path;
603                                                 return this.path.isPrefixOf(otherPath)
604                                                                 || otherPath.isPrefixOf(this.path);
605                                         } else {
606                                                 return false;
607                                         }
608                                 }
609                         }
610                         return new NoResourceSchedulingRule(getPath());
611                 } else {
612                         return resource;
613                 }
614         }
615
616         /**
617          * @see IParent
618          */
619         public boolean hasChildren() throws JavaModelException {
620                 // if I am not open, return true to avoid opening (case of a Java
621                 // project, a compilation unit or a class file).
622                 // also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
623                 Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(
624                                 this);
625                 if (elementInfo instanceof JavaElementInfo) {
626                         return ((JavaElementInfo) elementInfo).getChildren().length > 0;
627                 } else {
628                         return true;
629                 }
630         }
631
632         /**
633          * Returns the hash code for this Java element. By default, the hash code
634          * for an element is a combination of its name and parent's hash code.
635          * Elements with other requirements must override this method.
636          */
637         public int hashCode() {
638                 if (this.parent == null)
639                         return super.hashCode();
640                 return Util.combineHashCodes(this.name.hashCode(), this.parent
641                                 .hashCode());
642         }
643
644         /**
645          * Returns true if this element is an ancestor of the given element,
646          * otherwise false.
647          */
648         public boolean isAncestorOf(IJavaElement e) {
649                 IJavaElement parentElement = e.getParent();
650                 while (parentElement != null && !parentElement.equals(this)) {
651                         parentElement = parentElement.getParent();
652                 }
653                 return parentElement != null;
654         }
655
656         /**
657          * @see IJavaElement
658          */
659         public boolean isReadOnly() {
660                 return false;
661         }
662
663         /**
664          * @see IJavaElement
665          */
666         public boolean isStructureKnown() throws JavaModelException {
667                 return ((JavaElementInfo) getElementInfo()).isStructureKnown();
668         }
669
670         /**
671          * Creates and returns and not present exception for this element.
672          */
673         protected JavaModelException newNotPresentException() {
674                 return new JavaModelException(new JavaModelStatus(
675                                 IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
676         }
677
678         /**
679          * Opens this element and all parents that are not already open.
680          * 
681          * @exception JavaModelException
682          *                this element is not present or accessible
683          */
684         // protected void openHierarchy() throws JavaModelException {
685         // if (this instanceof IOpenable) {
686         // ((Openable) this).openWhenClosed(null);
687         // } else {
688         // Openable openableParent = (Openable)getOpenableParent();
689         // if (openableParent != null) {
690         // JavaElementInfo openableParentInfo = (JavaElementInfo)
691         // JavaModelManager.getJavaModelManager().getInfo((IJavaElement)
692         // openableParent);
693         // if (openableParentInfo == null) {
694         // openableParent.openWhenClosed(null);
695         // } else {
696         // throw newNotPresentException();
697         // }
698         // }
699         // }
700         // }
701         /**
702          * This element has just been opened. Do any necessary setup.
703          */
704         protected void opening(Object info) {
705         }
706
707         /*
708          * Opens an <code> Openable </code> that is known to be closed (no check for
709          * <code> isOpen() </code> ). Returns the created element info.
710          */
711         protected Object openWhenClosed(Object info, IProgressMonitor monitor)
712                         throws JavaModelException {
713                 JavaModelManager manager = JavaModelManager.getJavaModelManager();
714                 boolean hadTemporaryCache = manager.hasTemporaryCache();
715                 try {
716                         HashMap newElements = manager.getTemporaryCache();
717                         generateInfos(info, newElements, monitor);
718                         if (info == null) {
719                                 info = newElements.get(this);
720                         }
721                         if (info == null) { // a source ref element could not be opened
722                                 // close any buffer that was opened for the openable parent
723                                 Iterator iterator = newElements.keySet().iterator();
724                                 while (iterator.hasNext()) {
725                                         IJavaElement element = (IJavaElement) iterator.next();
726                                         if (element instanceof Openable) {
727                                                 ((Openable) element).closeBuffer();
728                                         }
729                                 }
730                                 throw newNotPresentException();
731                         }
732                         if (!hadTemporaryCache) {
733                                 manager.putInfos(this, newElements);
734                         }
735                 } finally {
736                         if (!hadTemporaryCache) {
737                                 manager.resetTemporaryCache();
738                         }
739                 }
740                 return info;
741         }
742
743         /**
744          */
745         public String readableName() {
746                 return this.getElementName();
747         }
748
749         /**
750          * Removes all cached info from the Java Model, including all children, but
751          * does not close this element.
752          */
753         // protected void removeInfo() {
754         // Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
755         // if (info != null) {
756         // if (this instanceof IParent) {
757         // IJavaElement[] children = ((JavaElementInfo)info).getChildren();
758         // for (int i = 0, size = children.length; i < size; ++i) {
759         // JavaElement child = (JavaElement) children[i];
760         // child.removeInfo();
761         // }
762         // }
763         // JavaModelManager.getJavaModelManager().removeInfo(this);
764         // }
765         // }
766         // /**
767         // * Returns a copy of this element rooted at the given project.
768         // */
769         // public abstract IJavaElement rootedAt(IJavaProject project);
770         /**
771          * Runs a Java Model Operation
772          */
773         public static void runOperation(JavaModelOperation operation,
774                         IProgressMonitor monitor) throws JavaModelException {
775                 try {
776                         if (operation.isReadOnly()
777                                         || ResourcesPlugin.getWorkspace().isTreeLocked()) {
778                                 operation.run(monitor);
779                         } else {
780                                 // use IWorkspace.run(...) to ensure that a build will be done
781                                 // in autobuild mode
782                                 ResourcesPlugin.getWorkspace().run(operation, monitor);
783                         }
784                 } catch (CoreException ce) {
785                         if (ce instanceof JavaModelException) {
786                                 throw (JavaModelException) ce;
787                         } else {
788                                 if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
789                                         Throwable e = ce.getStatus().getException();
790                                         if (e instanceof JavaModelException) {
791                                                 throw (JavaModelException) e;
792                                         }
793                                 }
794                                 throw new JavaModelException(ce);
795                         }
796                 }
797         }
798
799         /**
800          * Sets the occurrence count of the handle.
801          */
802         protected void setOccurrenceCount(int count) {
803                 occurrenceCount = count;
804         }
805
806         protected String tabString(int tab) {
807                 StringBuffer buffer = new StringBuffer();
808                 for (int i = tab; i > 0; i--)
809                         buffer.append("  "); //$NON-NLS-1$
810                 return buffer.toString();
811         }
812
813         /**
814          * Debugging purposes
815          */
816         public String toDebugString() {
817                 StringBuffer buffer = new StringBuffer();
818                 this.toStringInfo(0, buffer, NO_INFO);
819                 return buffer.toString();
820         }
821
822         /**
823          * Debugging purposes
824          */
825         public String toString() {
826                 StringBuffer buffer = new StringBuffer();
827                 toString(0, buffer);
828                 return buffer.toString();
829         }
830
831         /**
832          * Debugging purposes
833          */
834         protected void toStringName(StringBuffer buffer) {
835                 buffer.append(getElementName());
836                 if (this.occurrenceCount > 1) {
837                         buffer.append("#"); //$NON-NLS-1$
838                         buffer.append(this.occurrenceCount);
839                 }
840         }
841
842         /**
843          * Debugging purposes
844          */
845         protected void toString(int tab, StringBuffer buffer) {
846                 // Object info = this.toStringInfo(tab, buffer);
847                 Object info = null;
848                 if (tab == 0) {
849                         this.toStringAncestors(buffer);
850                 }
851                 this.toStringChildren(tab, buffer, info);
852         }
853
854         /**
855          * Debugging purposes
856          */
857         public String toStringWithAncestors() {
858                 StringBuffer buffer = new StringBuffer();
859                 this.toStringInfo(0, buffer, NO_INFO);
860                 this.toStringAncestors(buffer);
861                 return buffer.toString();
862         }
863
864         /**
865          * Debugging purposes
866          */
867         protected void toStringAncestors(StringBuffer buffer) {
868                 JavaElement parent = (JavaElement) this.getParent();
869                 if (parent != null && parent.getParent() != null) {
870                         buffer.append(" [in "); //$NON-NLS-1$
871                         parent.toStringInfo(0, buffer, NO_INFO);
872                         parent.toStringAncestors(buffer);
873                         buffer.append("]"); //$NON-NLS-1$
874                 }
875         }
876
877         /**
878          * Debugging purposes
879          */
880         protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
881                 if (info == null || !(info instanceof JavaElementInfo))
882                         return;
883                 IJavaElement[] children = ((JavaElementInfo) info).getChildren();
884                 for (int i = 0; i < children.length; i++) {
885                         buffer.append("\n"); //$NON-NLS-1$
886                         ((JavaElement) children[i]).toString(tab + 1, buffer);
887                 }
888         }
889
890         /**
891          * Debugging purposes
892          */
893         // public Object toStringInfo(int tab, StringBuffer buffer) {
894         // Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
895         // this.toStringInfo(tab, buffer, info);
896         // return info;
897         // }
898         /**
899          * Debugging purposes
900          */
901         protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
902                 buffer.append(this.tabString(tab));
903                 buffer.append(getElementName());
904                 if (info == null) {
905                         buffer.append(" (not open)"); //$NON-NLS-1$
906                 }
907         }
908 }