KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > JavaModelOperation


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core;
12
13 import java.io.InputStream JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16
17 import org.eclipse.core.resources.*;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.core.runtime.jobs.ISchedulingRule;
20 import org.eclipse.jdt.core.*;
21 import org.eclipse.jdt.internal.core.util.Messages;
22 import org.eclipse.jface.text.IDocument;
23
24 /**
25  * Defines behavior common to all Java Model operations
26  */

27 public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgressMonitor {
28     protected interface IPostAction {
29         /*
30          * Returns the id of this action.
31          * @see JavaModelOperation#postAction
32          */

33         String JavaDoc getID();
34         /*
35          * Run this action.
36          */

37         void run() throws JavaModelException;
38     }
39     /*
40      * Constants controlling the insertion mode of an action.
41      * @see JavaModelOperation#postAction
42      */

43     protected static final int APPEND = 1; // insert at the end
44
protected static final int REMOVEALL_APPEND = 2; // remove all existing ones with same ID, and add new one at the end
45
protected static final int KEEP_EXISTING = 3; // do not insert if already existing with same ID
46

47     /*
48      * Whether tracing post actions is enabled.
49      */

50     protected static boolean POST_ACTION_VERBOSE;
51
52     /*
53      * A list of IPostActions.
54      */

55     protected IPostAction[] actions;
56     protected int actionsStart = 0;
57     protected int actionsEnd = -1;
58     /*
59      * A HashMap of attributes that can be used by operations
60      */

61     protected HashMap JavaDoc attributes;
62
63     public static final String JavaDoc HAS_MODIFIED_RESOURCE_ATTR = "hasModifiedResource"; //$NON-NLS-1$
64
public static final String JavaDoc TRUE = JavaModelManager.TRUE;
65     //public static final String FALSE = "false";
66

67     /**
68      * The elements this operation operates on,
69      * or <code>null</code> if this operation
70      * does not operate on specific elements.
71      */

72     protected IJavaElement[] elementsToProcess;
73     /**
74      * The parent elements this operation operates with
75      * or <code>null</code> if this operation
76      * does not operate with specific parent elements.
77      */

78     protected IJavaElement[] parentElements;
79     /**
80      * An empty collection of <code>IJavaElement</code>s - the common
81      * empty result if no elements are created, or if this
82      * operation is not actually executed.
83      */

84     protected static IJavaElement[] NO_ELEMENTS= new IJavaElement[] {};
85
86
87     /**
88      * The elements created by this operation - empty
89      * until the operation actually creates elements.
90      */

91     protected IJavaElement[] resultElements= NO_ELEMENTS;
92
93     /**
94      * The progress monitor passed into this operation
95      */

96     public IProgressMonitor progressMonitor= null;
97     /**
98      * A flag indicating whether this operation is nested.
99      */

100     protected boolean isNested = false;
101     /**
102      * Conflict resolution policy - by default do not force (fail on a conflict).
103      */

104     protected boolean force = false;
105
106     /*
107      * A per thread stack of java model operations (PerThreadObject of ArrayList).
108      */

109     protected static ThreadLocal JavaDoc operationStacks = new ThreadLocal JavaDoc();
110     protected JavaModelOperation() {
111         // default constructor used in subclasses
112
}
113     /**
114      * A common constructor for all Java Model operations.
115      */

116     protected JavaModelOperation(IJavaElement[] elements) {
117         this.elementsToProcess = elements;
118     }
119     /**
120      * Common constructor for all Java Model operations.
121      */

122     protected JavaModelOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements) {
123         this.elementsToProcess = elementsToProcess;
124         this.parentElements= parentElements;
125     }
126     /**
127      * A common constructor for all Java Model operations.
128      */

129     protected JavaModelOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements, boolean force) {
130         this.elementsToProcess = elementsToProcess;
131         this.parentElements= parentElements;
132         this.force= force;
133     }
134     /**
135      * A common constructor for all Java Model operations.
136      */

137     protected JavaModelOperation(IJavaElement[] elements, boolean force) {
138         this.elementsToProcess = elements;
139         this.force= force;
140     }
141     
142     /**
143      * Common constructor for all Java Model operations.
144      */

145     protected JavaModelOperation(IJavaElement element) {
146         this.elementsToProcess = new IJavaElement[]{element};
147     }
148     /**
149      * A common constructor for all Java Model operations.
150      */

151     protected JavaModelOperation(IJavaElement element, boolean force) {
152         this.elementsToProcess = new IJavaElement[]{element};
153         this.force= force;
154     }
155     
156     /*
157      * Registers the given action at the end of the list of actions to run.
158      */

159     protected void addAction(IPostAction action) {
160         int length = this.actions.length;
161         if (length == ++this.actionsEnd) {
162             System.arraycopy(this.actions, 0, this.actions = new IPostAction[length*2], 0, length);
163         }
164         this.actions[this.actionsEnd] = action;
165     }
166     /*
167      * Registers the given delta with the Java Model Manager.
168      */

169     protected void addDelta(IJavaElementDelta delta) {
170         JavaModelManager.getJavaModelManager().getDeltaProcessor().registerJavaModelDelta(delta);
171     }
172     /*
173      * Registers the given reconcile delta with the Java Model Manager.
174      */

175     protected void addReconcileDelta(ICompilationUnit workingCopy, IJavaElementDelta delta) {
176         HashMap JavaDoc reconcileDeltas = JavaModelManager.getJavaModelManager().getDeltaProcessor().reconcileDeltas;
177         JavaElementDelta previousDelta = (JavaElementDelta)reconcileDeltas.get(workingCopy);
178         if (previousDelta != null) {
179             IJavaElementDelta[] children = delta.getAffectedChildren();
180             for (int i = 0, length = children.length; i < length; i++) {
181                 JavaElementDelta child = (JavaElementDelta)children[i];
182                 previousDelta.insertDeltaTree(child.getElement(), child);
183             }
184             // note that the last delta's AST always takes precedence over the existing delta's AST
185
// since it is the result of the last reconcile operation
186
if ((delta.getFlags() & IJavaElementDelta.F_AST_AFFECTED) != 0) {
187                 previousDelta.changedAST(delta.getCompilationUnitAST());
188             }
189                         
190         } else {
191             reconcileDeltas.put(workingCopy, delta);
192         }
193     }
194     /*
195      * Deregister the reconcile delta for the given working copy
196      */

197     protected void removeReconcileDelta(ICompilationUnit workingCopy) {
198         JavaModelManager.getJavaModelManager().getDeltaProcessor().reconcileDeltas.remove(workingCopy);
199     }
200     /**
201      * @see IProgressMonitor
202      */

203     public void beginTask(String JavaDoc name, int totalWork) {
204         if (progressMonitor != null) {
205             progressMonitor.beginTask(name, totalWork);
206         }
207     }
208     /*
209      * Returns whether this operation can modify the package fragment roots.
210      */

211     protected boolean canModifyRoots() {
212         return false;
213     }
214     /**
215      * Checks with the progress monitor to see whether this operation
216      * should be canceled. An operation should regularly call this method
217      * during its operation so that the user can cancel it.
218      *
219      * @exception OperationCanceledException if cancelling the operation has been requested
220      * @see IProgressMonitor#isCanceled
221      */

222     protected void checkCanceled() {
223         if (isCanceled()) {
224             throw new OperationCanceledException(Messages.operation_cancelled);
225         }
226     }
227     /**
228      * Common code used to verify the elements this operation is processing.
229      * @see JavaModelOperation#verify()
230      */

231     protected IJavaModelStatus commonVerify() {
232         if (elementsToProcess == null || elementsToProcess.length == 0) {
233             return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
234         }
235         for (int i = 0; i < elementsToProcess.length; i++) {
236             if (elementsToProcess[i] == null) {
237                 return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
238             }
239         }
240         return JavaModelStatus.VERIFIED_OK;
241     }
242     /**
243      * Convenience method to copy resources
244      */

245     protected void copyResources(IResource[] resources, IPath destinationPath) throws JavaModelException {
246         IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length);
247         IWorkspace workspace = resources[0].getWorkspace();
248         try {
249             workspace.copy(resources, destinationPath, false, subProgressMonitor);
250             setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
251         } catch (CoreException e) {
252             throw new JavaModelException(e);
253         }
254     }
255     /**
256      * Convenience method to create a file
257      */

258     protected void createFile(IContainer folder, String JavaDoc name, InputStream JavaDoc contents, boolean forceFlag) throws JavaModelException {
259         IFile file= folder.getFile(new Path(name));
260         try {
261             file.create(
262                 contents,
263                 forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
264                 getSubProgressMonitor(1));
265                 setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
266         } catch (CoreException e) {
267             throw new JavaModelException(e);
268         }
269     }
270     /**
271      * Convenience method to create a folder
272      */

273     protected void createFolder(IContainer parentFolder, String JavaDoc name, boolean forceFlag) throws JavaModelException {
274         IFolder folder= parentFolder.getFolder(new Path(name));
275         try {
276             // we should use true to create the file locally. Only VCM should use tru/false
277
folder.create(
278                 forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
279                 true, // local
280
getSubProgressMonitor(1));
281             setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
282         } catch (CoreException e) {
283             throw new JavaModelException(e);
284         }
285     }
286     /**
287      * Convenience method to delete an empty package fragment
288      */

289     protected void deleteEmptyPackageFragment(
290         IPackageFragment fragment,
291         boolean forceFlag,
292         IResource rootResource)
293         throws JavaModelException {
294     
295         IContainer resource = (IContainer) fragment.getResource();
296     
297         try {
298             resource.delete(
299                 forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
300                 getSubProgressMonitor(1));
301             setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
302             while (resource instanceof IFolder) {
303                 // deleting a package: delete the parent if it is empty (eg. deleting x.y where folder x doesn't have resources but y)
304
// without deleting the package fragment root
305
resource = resource.getParent();
306                 if (!resource.equals(rootResource) && resource.members().length == 0) {
307                     resource.delete(
308                         forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
309                         getSubProgressMonitor(1));
310                     setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
311                 }
312             }
313         } catch (CoreException e) {
314             throw new JavaModelException(e);
315         }
316     }
317     /**
318      * Convenience method to delete a resource
319      */

320     protected void deleteResource(IResource resource,int flags) throws JavaModelException {
321         try {
322             resource.delete(flags, getSubProgressMonitor(1));
323             setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
324         } catch (CoreException e) {
325             throw new JavaModelException(e);
326         }
327     }
328     /**
329      * Convenience method to delete resources
330      */

331     protected void deleteResources(IResource[] resources, boolean forceFlag) throws JavaModelException {
332         if (resources == null || resources.length == 0) return;
333         IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length);
334         IWorkspace workspace = resources[0].getWorkspace();
335         try {
336             workspace.delete(
337                 resources,
338                 forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
339                 subProgressMonitor);
340                 setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
341         } catch (CoreException e) {
342             throw new JavaModelException(e);
343         }
344     }
345     /**
346      * @see IProgressMonitor
347      */

348     public void done() {
349         if (progressMonitor != null) {
350             progressMonitor.done();
351         }
352     }
353     /*
354      * Returns whether the given path is equals to one of the given other paths.
355      */

356     protected boolean equalsOneOf(IPath path, IPath[] otherPaths) {
357         for (int i = 0, length = otherPaths.length; i < length; i++) {
358             if (path.equals(otherPaths[i])) {
359                 return true;
360             }
361         }
362         return false;
363     }
364     /**
365      * Convenience method to run an operation within this operation
366      */

367     public void executeNestedOperation(JavaModelOperation operation, int subWorkAmount) throws JavaModelException {
368         IJavaModelStatus status= operation.verify();
369         if (!status.isOK()) {
370             throw new JavaModelException(status);
371         }
372         IProgressMonitor subProgressMonitor = getSubProgressMonitor(subWorkAmount);
373         // fix for 1FW7IKC, part (1)
374
try {
375             operation.setNested(true);
376             operation.run(subProgressMonitor);
377         } catch (CoreException ce) {
378             if (ce instanceof JavaModelException) {
379                 throw (JavaModelException)ce;
380             } else {
381                 // translate the core exception to a java model exception
382
if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
383                     Throwable JavaDoc e = ce.getStatus().getException();
384                     if (e instanceof JavaModelException) {
385                         throw (JavaModelException) e;
386                     }
387                 }
388                 throw new JavaModelException(ce);
389             }
390         }
391     }
392     /**
393      * Performs the operation specific behavior. Subclasses must override.
394      */

395     protected abstract void executeOperation() throws JavaModelException;
396     /*
397      * Returns the attribute registered at the given key with the top level operation.
398      * Returns null if no such attribute is found.
399      */

400     protected static Object JavaDoc getAttribute(Object JavaDoc key) {
401         ArrayList JavaDoc stack = getCurrentOperationStack();
402         if (stack.size() == 0) return null;
403         JavaModelOperation topLevelOp = (JavaModelOperation)stack.get(0);
404         if (topLevelOp.attributes == null) {
405             return null;
406         } else {
407             return topLevelOp.attributes.get(key);
408         }
409     }
410     /**
411      * Returns the compilation unit the given element is contained in,
412      * or the element itself (if it is a compilation unit),
413      * otherwise <code>null</code>.
414      */

415     protected ICompilationUnit getCompilationUnitFor(IJavaElement element) {
416     
417         return ((JavaElement)element).getCompilationUnit();
418     }
419     /*
420      * Returns the stack of operations running in the current thread.
421      * Returns an empty stack if no operations are currently running in this thread.
422      */

423     protected static ArrayList JavaDoc getCurrentOperationStack() {
424         ArrayList JavaDoc stack = (ArrayList JavaDoc)operationStacks.get();
425         if (stack == null) {
426             stack = new ArrayList JavaDoc();
427             operationStacks.set(stack);
428         }
429         return stack;
430     }
431     /*
432      * Returns the existing document for the given cu, or a DocumentAdapter if none.
433      */

434     protected IDocument getDocument(ICompilationUnit cu) throws JavaModelException {
435         IBuffer buffer = cu.getBuffer();
436         if (buffer instanceof IDocument)
437             return (IDocument) buffer;
438         return new DocumentAdapter(buffer);
439     }
440     /**
441      * Returns the elements to which this operation applies,
442      * or <code>null</code> if not applicable.
443      */

444     protected IJavaElement[] getElementsToProcess() {
445         return elementsToProcess;
446     }
447     /**
448      * Returns the element to which this operation applies,
449      * or <code>null</code> if not applicable.
450      */

451     protected IJavaElement getElementToProcess() {
452         if (elementsToProcess == null || elementsToProcess.length == 0) {
453             return null;
454         }
455         return elementsToProcess[0];
456     }
457     /**
458      * Returns the Java Model this operation is operating in.
459      */

460     public IJavaModel getJavaModel() {
461         return JavaModelManager.getJavaModelManager().getJavaModel();
462     }
463     protected IPath[] getNestedFolders(IPackageFragmentRoot root) throws JavaModelException {
464         IPath rootPath = root.getPath();
465         IClasspathEntry[] classpath = root.getJavaProject().getRawClasspath();
466         int length = classpath.length;
467         IPath[] result = new IPath[length];
468         int index = 0;
469         for (int i = 0; i < length; i++) {
470             IPath path = classpath[i].getPath();
471             if (rootPath.isPrefixOf(path) && !rootPath.equals(path)) {
472                 result[index++] = path;
473             }
474         }
475         if (index < length) {
476             System.arraycopy(result, 0, result = new IPath[index], 0, index);
477         }
478         return result;
479     }
480     /**
481      * Returns the parent element to which this operation applies,
482      * or <code>null</code> if not applicable.
483      */

484     protected IJavaElement getParentElement() {
485         if (parentElements == null || parentElements.length == 0) {
486             return null;
487         }
488         return parentElements[0];
489     }
490     /**
491      * Returns the parent elements to which this operation applies,
492      * or <code>null</code> if not applicable.
493      */

494     protected IJavaElement[] getParentElements() {
495         return parentElements;
496     }
497     /**
498      * Returns the elements created by this operation.
499      */

500     public IJavaElement[] getResultElements() {
501         return resultElements;
502     }
503     /*
504      * Returns the scheduling rule for this operation (i.e. the resource that needs to be locked
505      * while this operation is running.
506      * Subclasses can override.
507      */

508     protected ISchedulingRule getSchedulingRule() {
509         return ResourcesPlugin.getWorkspace().getRoot();
510     }
511     /**
512      * Creates and returns a subprogress monitor if appropriate.
513      */

514     protected IProgressMonitor getSubProgressMonitor(int workAmount) {
515         IProgressMonitor sub = null;
516         if (progressMonitor != null) {
517             sub = new SubProgressMonitor(progressMonitor, workAmount, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
518         }
519         return sub;
520     }
521
522     /**
523      * Returns whether this operation has performed any resource modifications.
524      * Returns false if this operation has not been executed yet.
525      */

526     public boolean hasModifiedResource() {
527         return !this.isReadOnly() && getAttribute(HAS_MODIFIED_RESOURCE_ATTR) == TRUE;
528     }
529     public void internalWorked(double work) {
530         if (progressMonitor != null) {
531             progressMonitor.internalWorked(work);
532         }
533     }
534     /**
535      * @see IProgressMonitor
536      */

537     public boolean isCanceled() {
538         if (progressMonitor != null) {
539             return progressMonitor.isCanceled();
540         }
541         return false;
542     }
543     /**
544      * Returns <code>true</code> if this operation performs no resource modifications,
545      * otherwise <code>false</code>. Subclasses must override.
546      */

547     public boolean isReadOnly() {
548         return false;
549     }
550     /*
551      * Returns whether this operation is the first operation to run in the current thread.
552      */

553     protected boolean isTopLevelOperation() {
554         ArrayList JavaDoc stack;
555         return
556             (stack = getCurrentOperationStack()).size() > 0
557             && stack.get(0) == this;
558     }
559     /*
560      * Returns the index of the first registered action with the given id, starting from a given position.
561      * Returns -1 if not found.
562      */

563     protected int firstActionWithID(String JavaDoc id, int start) {
564         for (int i = start; i <= this.actionsEnd; i++) {
565             if (this.actions[i].getID().equals(id)) {
566                 return i;
567             }
568         }
569         return -1;
570     }
571     
572     /**
573      * Convenience method to move resources
574      */

575     protected void moveResources(IResource[] resources, IPath destinationPath) throws JavaModelException {
576         IProgressMonitor subProgressMonitor = null;
577         if (progressMonitor != null) {
578             subProgressMonitor = new SubProgressMonitor(progressMonitor, resources.length, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
579         }
580         IWorkspace workspace = resources[0].getWorkspace();
581         try {
582             workspace.move(resources, destinationPath, false, subProgressMonitor);
583             setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
584         } catch (CoreException e) {
585             throw new JavaModelException(e);
586         }
587     }
588     /**
589      * Creates and returns a new <code>IJavaElementDelta</code>
590      * on the Java Model.
591      */

592     public JavaElementDelta newJavaElementDelta() {
593         return new JavaElementDelta(getJavaModel());
594     }
595     /*
596      * Removes the last pushed operation from the stack of running operations.
597      * Returns the poped operation or null if the stack was empty.
598      */

599     protected JavaModelOperation popOperation() {
600         ArrayList JavaDoc stack = getCurrentOperationStack();
601         int size = stack.size();
602         if (size > 0) {
603             if (size == 1) { // top level operation
604
operationStacks.set(null); // release reference (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=33927)
605
}
606             return (JavaModelOperation)stack.remove(size-1);
607         } else {
608             return null;
609         }
610     }
611     /*
612      * Registers the given action to be run when the outer most java model operation has finished.
613      * The insertion mode controls whether:
614      * - the action should discard all existing actions with the same id, and be queued at the end (REMOVEALL_APPEND),
615      * - the action should be ignored if there is already an action with the same id (KEEP_EXISTING),
616      * - the action should be queued at the end without looking at existing actions (APPEND)
617      */

618     protected void postAction(IPostAction action, int insertionMode) {
619         if (POST_ACTION_VERBOSE) {
620             System.out.print("(" + Thread.currentThread() + ") [JavaModelOperation.postAction(IPostAction, int)] Posting action " + action.getID()); //$NON-NLS-1$ //$NON-NLS-2$
621
switch(insertionMode) {
622                 case REMOVEALL_APPEND:
623                     System.out.println(" (REMOVEALL_APPEND)"); //$NON-NLS-1$
624
break;
625                 case KEEP_EXISTING:
626                     System.out.println(" (KEEP_EXISTING)"); //$NON-NLS-1$
627
break;
628                 case APPEND:
629                     System.out.println(" (APPEND)"); //$NON-NLS-1$
630
break;
631             }
632         }
633         
634         JavaModelOperation topLevelOp = (JavaModelOperation)getCurrentOperationStack().get(0);
635         IPostAction[] postActions = topLevelOp.actions;
636         if (postActions == null) {
637             topLevelOp.actions = postActions = new IPostAction[1];
638             postActions[0] = action;
639             topLevelOp.actionsEnd = 0;
640         } else {
641             String JavaDoc id = action.getID();
642             switch (insertionMode) {
643                 case REMOVEALL_APPEND :
644                     int index = this.actionsStart-1;
645                     while ((index = topLevelOp.firstActionWithID(id, index+1)) >= 0) {
646                         // remove action[index]
647
System.arraycopy(postActions, index+1, postActions, index, topLevelOp.actionsEnd - index);
648                         postActions[topLevelOp.actionsEnd--] = null;
649                     }
650                     topLevelOp.addAction(action);
651                     break;
652                 case KEEP_EXISTING:
653                     if (topLevelOp.firstActionWithID(id, 0) < 0) {
654                         topLevelOp.addAction(action);
655                     }
656                     break;
657                 case APPEND:
658                     topLevelOp.addAction(action);
659                     break;
660             }
661         }
662     }
663     /*
664      * Returns whether the given path is the prefix of one of the given other paths.
665      */

666     protected boolean prefixesOneOf(IPath path, IPath[] otherPaths) {
667         for (int i = 0, length = otherPaths.length; i < length; i++) {
668             if (path.isPrefixOf(otherPaths[i])) {
669                 return true;
670             }
671         }
672         return false;
673     }
674     /*
675      * Pushes the given operation on the stack of operations currently running in this thread.
676      */

677     protected void pushOperation(JavaModelOperation operation) {
678         getCurrentOperationStack().add(operation);
679     }
680     /*
681      * Removes all actions with the given id from the queue of post actions.
682      * Does nothing if no such action is in the queue.
683      */

684     protected void removeAllPostAction(String JavaDoc actionID) {
685         if (POST_ACTION_VERBOSE) {
686             System.out.println("(" + Thread.currentThread() + ") [JavaModelOperation.removeAllPostAction(String)] Removing actions " + actionID); //$NON-NLS-1$ //$NON-NLS-2$
687
}
688         
689         JavaModelOperation topLevelOp = (JavaModelOperation)getCurrentOperationStack().get(0);
690         IPostAction[] postActions = topLevelOp.actions;
691         if (postActions == null) return;
692         int index = this.actionsStart-1;
693         while ((index = topLevelOp.firstActionWithID(actionID, index+1)) >= 0) {
694             // remove action[index]
695
System.arraycopy(postActions, index+1, postActions, index, topLevelOp.actionsEnd - index);
696             postActions[topLevelOp.actionsEnd--] = null;
697         }
698     }
699     
700     /**
701      * Runs this operation and registers any deltas created.
702      *
703      * @see IWorkspaceRunnable
704      * @exception CoreException if the operation fails
705      */

706     public void run(IProgressMonitor monitor) throws CoreException {
707         JavaModelManager manager = JavaModelManager.getJavaModelManager();
708         DeltaProcessor deltaProcessor = manager.getDeltaProcessor();
709         int previousDeltaCount = deltaProcessor.javaModelDeltas.size();
710         try {
711             progressMonitor = monitor;
712             pushOperation(this);
713             try {
714                 if (canModifyRoots()) {
715                     // computes the root infos before executing the operation
716
// noop if aready initialized
717
JavaModelManager.getJavaModelManager().deltaState.initializeRoots();
718                 }
719                 
720                 executeOperation();
721             } finally {
722                 if (this.isTopLevelOperation()) {
723                     this.runPostActions();
724                 }
725             }
726         } finally {
727             try {
728                 // reacquire delta processor as it can have been reset during executeOperation()
729
deltaProcessor = manager.getDeltaProcessor();
730                 
731                 // update JavaModel using deltas that were recorded during this operation
732
for (int i = previousDeltaCount, size = deltaProcessor.javaModelDeltas.size(); i < size; i++) {
733                     deltaProcessor.updateJavaModel((IJavaElementDelta)deltaProcessor.javaModelDeltas.get(i));
734                 }
735                 
736                 // close the parents of the created elements and reset their project's cache (in case we are in an
737
// IWorkspaceRunnable and the clients wants to use the created element's parent)
738
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=83646
739
for (int i = 0, length = this.resultElements.length; i < length; i++) {
740                     IJavaElement element = this.resultElements[i];
741                     Openable openable = (Openable) element.getOpenable();
742                     if (!(openable instanceof CompilationUnit) || !((CompilationUnit) openable).isWorkingCopy()) { // a working copy must remain a child of its parent even after a move
743
((JavaElement) openable.getParent()).close();
744                     }
745                     switch (element.getElementType()) {
746                         case IJavaElement.PACKAGE_FRAGMENT_ROOT:
747                         case IJavaElement.PACKAGE_FRAGMENT:
748                             deltaProcessor.projectCachesToReset.add(element.getJavaProject());
749                             break;
750                     }
751                 }
752                 deltaProcessor.resetProjectCaches();
753                 
754                 // fire only iff:
755
// - the operation is a top level operation
756
// - the operation did produce some delta(s)
757
// - but the operation has not modified any resource
758
if (this.isTopLevelOperation()) {
759                     if ((deltaProcessor.javaModelDeltas.size() > previousDeltaCount || !deltaProcessor.reconcileDeltas.isEmpty())
760                             && !this.hasModifiedResource()) {
761                         deltaProcessor.fire(null, DeltaProcessor.DEFAULT_CHANGE_EVENT);
762                     } // else deltas are fired while processing the resource delta
763
}
764             } finally {
765                 popOperation();
766             }
767         }
768     }
769     /**
770      * Main entry point for Java Model operations. Runs a Java Model Operation as an IWorkspaceRunnable
771      * if not read-only.
772      */

773     public void runOperation(IProgressMonitor monitor) throws JavaModelException {
774         IJavaModelStatus status= verify();
775         if (!status.isOK()) {
776             throw new JavaModelException(status);
777         }
778         try {
779             if (isReadOnly()) {
780                 run(monitor);
781             } else {
782                 // Use IWorkspace.run(...) to ensure that a build will be done in autobuild mode.
783
// Note that if the tree is locked, this will throw a CoreException, but this is ok
784
// as this operation is modifying the tree (not read-only) and a CoreException will be thrown anyway.
785
ResourcesPlugin.getWorkspace().run(this, getSchedulingRule(), IWorkspace.AVOID_UPDATE, monitor);
786             }
787         } catch (CoreException ce) {
788             if (ce instanceof JavaModelException) {
789                 throw (JavaModelException)ce;
790             } else {
791                 if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
792                     Throwable JavaDoc e= ce.getStatus().getException();
793                     if (e instanceof JavaModelException) {
794                         throw (JavaModelException) e;
795                     }
796                 }
797                 throw new JavaModelException(ce);
798             }
799         }
800     }
801     protected void runPostActions() throws JavaModelException {
802         while (this.actionsStart <= this.actionsEnd) {
803             IPostAction postAction = this.actions[this.actionsStart++];
804             if (POST_ACTION_VERBOSE) {
805                 System.out.println("(" + Thread.currentThread() + ") [JavaModelOperation.runPostActions()] Running action " + postAction.getID()); //$NON-NLS-1$ //$NON-NLS-2$
806
}
807             postAction.run();
808         }
809     }
810     /*
811      * Registers the given attribute at the given key with the top level operation.
812      */

813     protected static void setAttribute(Object JavaDoc key, Object JavaDoc attribute) {
814         ArrayList JavaDoc operationStack = getCurrentOperationStack();
815         if (operationStack.size() == 0)
816             return;
817         JavaModelOperation topLevelOp = (JavaModelOperation) operationStack.get(0);
818         if (topLevelOp.attributes == null) {
819             topLevelOp.attributes = new HashMap JavaDoc();
820         }
821         topLevelOp.attributes.put(key, attribute);
822     }
823     /**
824      * @see IProgressMonitor
825      */

826     public void setCanceled(boolean b) {
827         if (progressMonitor != null) {
828             progressMonitor.setCanceled(b);
829         }
830     }
831     /**
832      * Sets whether this operation is nested or not.
833      * @see CreateElementInCUOperation#checkCanceled
834      */

835     protected void setNested(boolean nested) {
836         isNested = nested;
837     }
838     /**
839      * @see IProgressMonitor
840      */

841     public void setTaskName(String JavaDoc name) {
842         if (progressMonitor != null) {
843             progressMonitor.setTaskName(name);
844         }
845     }
846     /**
847      * @see IProgressMonitor
848      */

849     public void subTask(String JavaDoc name) {
850         if (progressMonitor != null) {
851             progressMonitor.subTask(name);
852         }
853     }
854     /**
855      * Returns a status indicating if there is any known reason
856      * this operation will fail. Operations are verified before they
857      * are run.
858      *
859      * Subclasses must override if they have any conditions to verify
860      * before this operation executes.
861      *
862      * @see IJavaModelStatus
863      */

864     protected IJavaModelStatus verify() {
865         return commonVerify();
866     }
867     
868     /**
869      * @see IProgressMonitor
870      */

871     public void worked(int work) {
872         if (progressMonitor != null) {
873             progressMonitor.worked(work);
874             checkCanceled();
875         }
876     }
877 }
878
Popular Tags