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