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