KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ltk > core > refactoring > Change


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.ltk.core.refactoring;
12
13 import org.eclipse.core.runtime.Assert;
14 import org.eclipse.core.runtime.CoreException;
15 import org.eclipse.core.runtime.IAdaptable;
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.OperationCanceledException;
18 import org.eclipse.core.runtime.Platform;
19
20 /**
21  * An abstract base implementation for object representing a generic change
22  * to the workbench. A <code>Change</code> object is typically created by
23  * calling <code>Refactoring.createChange()</code>. This class should be
24  * subclassed by clients wishing to provide new changes.
25  * <p>
26  * Changes are best executed by using a {@link PerformChangeOperation}. If clients
27  * execute a change directly then the following life cycle has to be honored:
28  * <ul>
29  * <li>After a single change or a tree of changes has been created, the
30  * method <code>initializeValidationState</code> has to be called.</li>
31  * <li>The method <code>isValid</code> can be used to determine if a change
32  * can still be applied to the workspace. If the method returns a {@link
33  * RefactoringStatus} with a severity of FATAL then the change has to be
34  * treated as invalid. Performing an invalid change isn't allowed and
35  * results in an unspecified result. This method can be called multiple
36  * times.
37  * <li>Then the method <code>perform</code> can be called. A disabled change
38  * must not be executed. The <code>perform</code> method can only be called
39  * once. After a change has been executed, only the method <code>dispose</code>
40  * must be called.</li>
41  * <li>the method <code>dispose</code> has to be called either after the
42  * <code>perform</code> method
43  * has been called or if a change is no longer needed. The second case
44  * for example occurs when the undo stack gets flushed and all change
45  * objects managed by the undo stack are no longer needed. The method
46  * <code>dispose</code> is typically implemented to unregister listeners
47  * registered during the
48  * method <code>initializeValidationState</code>. There is no guarantee
49  * that <code>initializeValidationState</code>, <code>isValid</code>,
50  * or <code>perform</code> has been called before <code>dispose</code>
51  * is called.
52  * </ul>
53  * Here is a code snippet that can be used to execute a change:
54  * <pre>
55  * Change change= createChange();
56  * try {
57  * change.initializeValidationState(pm);
58  *
59  * ....
60  *
61  * if (!change.isEnabled())
62  * return;
63  * RefactoringStatus valid= change.isValid(new SubProgressMonitor(pm, 1));
64  * if (valid.hasFatalError())
65  * return;
66  * Change undo= change.perform(new SubProgressMonitor(pm, 1));
67  * if (undo != null) {
68  * undo.initializeValidationState(new SubProgressMonitor(pm, 1));
69  * // do something with the undo object
70  * }
71  * } finally {
72  * change.dispose();
73  * }
74  * </pre>
75  * </p>
76  * <p>
77  * It is important that implementors of this abstract class provide an adequate
78  * implementation of <code>isValid</code> and that they provide an undo change
79  * via the return value of the method <code>perform</code>. If no undo can be
80  * provided then the <code>perform</code> method is allowed to return <code>null</code>. But
81  * implementors should be aware that not providing an undo object for a change
82  * object that is part of a larger change tree will result in the fact that for
83  * the whole change tree no undo object will be present.
84  * </p>
85  * <p>
86  * Changes which are returned as top-level changes (e.g. by <code>Refactoring.createChange()</code>)
87  * can optionally return a descriptor object of the refactoring which created this change object.
88  * </p>
89  * <p>
90  * Clients may subclass this class.
91  * </p>
92  *
93  * @since 3.0
94  */

95 public abstract class Change implements IAdaptable {
96
97     private Change fParent;
98     private boolean fIsEnabled= true;
99     
100     /**
101      * Constructs a new change object.
102      */

103     protected Change() {
104     }
105     
106     /**
107      * Returns a descriptor of this change.
108      * <p>
109      * Subclasses of changes created by
110      * {@link Refactoring#createChange(IProgressMonitor)} should override this
111      * method to return a {@link RefactoringChangeDescriptor}. A change tree
112      * created by a particular refactoring is supposed to contain at most one
113      * change which returns a refactoring descriptor. Refactorings usually
114      * return an instance of {@link CompositeChange} in their
115      * {@link Refactoring#createChange(IProgressMonitor)} method which
116      * implements this method. The refactoring framework searches the change
117      * tree top-down until a refactoring descriptor is found.
118      * </p>
119      *
120      * @return a descriptor of this change, or <code>null</code> if this
121      * change does not provide a change descriptor.
122      *
123      * @since 3.2
124      */

125     public ChangeDescriptor getDescriptor() {
126         return null;
127     }
128
129     /**
130      * Returns the human readable name of this change. The
131      * name <em>MUST</em> not be <code>null</code>.
132      *
133      * @return the human readable name of this change
134      */

135     public abstract String JavaDoc getName();
136     
137     /**
138      * Returns whether this change is enabled or not. Disabled changes
139      * must not be executed.
140      *
141      * @return <code>true</code> if the change is enabled; <code>false</code>
142      * otherwise.
143      */

144     public boolean isEnabled() {
145         return fIsEnabled;
146     }
147     
148     /**
149      * Sets whether this change is enabled or not.
150      *
151      * @param enabled <code>true</code> to enable this change; <code>
152      * false</code> otherwise
153      */

154     public void setEnabled(boolean enabled) {
155         fIsEnabled= enabled;
156     }
157     
158     /**
159      * Sets the enablement state of this change in a shallow way.
160      * For changes having children this means that only this change's
161      * enablement state changes. The children are left untouched.
162      *
163      * @param enabled <code>true</code> to enable this change; <code>
164      * false</code> otherwise
165      *
166      * @since 3.1
167      */

168     public final void setEnabledShallow(boolean enabled) {
169         fIsEnabled= enabled;
170     }
171     
172     /**
173      * Returns the parent change. Returns <code>null</code> if no
174      * parent exists.
175      *
176      * @return the parent change
177      */

178     public Change getParent() {
179         return fParent;
180     }
181     
182     /**
183      * Sets the parent of this change. Requires that this change isn't already
184      * connected to a parent. The parent can be <code>null</code> to disconnect
185      * this change from a parent.
186      *
187      * @param parent the parent of this change or <code>null</code>
188      */

189     /* package */ void setParent(Change parent) {
190         if (parent != null)
191             Assert.isTrue(fParent == null);
192         fParent= parent;
193     }
194     
195     /**
196      * Hook method to initialize some internal state to provide an adequate answer
197      * for the <code>isValid</code> method. This method gets called after a change
198      * or a whole change tree has been created.
199      * <p>
200      * Typically this method is implemented in one of the following ways:
201      * <ul>
202      * <li>the change hooks up a listener on some delta notification mechanism
203      * and marks itself as invalid if it receives a certain delta. Is this
204      * the case the implementor must take care of unhooking the listener
205      * in <code>dispose</code>.</li>
206      * <li>the change remembers some information allowing to decide if a change
207      * object is still valid when <code>isValid</code> is called.</li>
208      * </ul>
209      * <p>
210      * For example, a change object that manipulates the content of an <code>IFile</code>
211      * could either listen to resource changes and detect that the file got changed or
212      * it could remember some content stamp and compare it with the actual content stamp
213      * when <code>isValid</code> is called.
214      * </p>
215      *
216      * @param pm a progress monitor
217      */

218     public abstract void initializeValidationData(IProgressMonitor pm);
219     
220     /**
221      * Verifies that this change object is still valid and can be executed by calling
222      * <code>perform</code>. If a refactoring status with a severity of {@link
223      * RefactoringStatus#FATAL} is returned then the change has to be treated as invalid
224      * and can no longer be executed. Performing such a change produces an unspecified
225      * result and will very likely throw an exception.
226      * <p>
227      * This method is also called by the {@link IUndoManager UndoManager} to decide if
228      * an undo or redo change is still valid and therefore can be executed.
229      * </p>
230      *
231      * @param pm a progress monitor.
232      *
233      * @return a refactoring status describing the outcome of the validation check
234      *
235      * @throws CoreException if an error occurred during validation check. The change
236      * is to be treated as invalid if an exception occurs
237      *
238      * @throws OperationCanceledException if the validation check got canceled
239      */

240     public abstract RefactoringStatus isValid(IProgressMonitor pm) throws CoreException, OperationCanceledException;
241     
242     /**
243      * Performs this change. If this method is call on an invalid or disabled change
244      * object the result is unspecified. Changes should in general not respond to
245      * {@link IProgressMonitor#isCanceled()} since canceling a change tree in the
246      * middle of its execution leaves the workspace in a half changed state.
247      *
248      * @param pm a progress monitor
249      *
250      * @return the undo change for this change object or <code>null</code> if no
251      * undo is provided
252      *
253      * @throws CoreException if an error occurred during change execution
254      */

255     public abstract Change perform(IProgressMonitor pm) throws CoreException;
256     
257     /**
258      * Disposes this change. Subclasses that override this method typically
259      * unregister listeners which got registered during the call to <code>
260      * initializeValidationState</code>.
261      * <p>
262      * Subclasses may override this method.
263      * </p>
264      */

265     public void dispose() {
266         // empty default implementation
267
}
268      
269     /**
270      * Returns the element modified by this <code>Change</code>. The method may return
271      * <code>null</code> if the change isn't related to an element.
272      *
273      * @return the element modified by this change
274      */

275     public abstract Object JavaDoc getModifiedElement();
276
277     /**
278      * Returns the elements affected by this change or <code>null</code> if
279      * the affected elements cannot be determined. Returns an empty array
280      * if the change doesn't modify any elements.
281      * <p>
282      * This default implementation returns <code>null</code> to indicate that
283      * the affected elements are unknown. Subclasses should reimplement this method
284      * if they can compute the set of affected elements.
285      * </p>
286      *
287      * @return the elements affected by this change or <code>null</code> if
288      * the affected elements cannot be determined
289      *
290      * @since 3.1
291      */

292     public Object JavaDoc[] getAffectedObjects() {
293         return null;
294     }
295     
296     /**
297      * {@inheritDoc}
298      */

299     public Object JavaDoc getAdapter(Class JavaDoc adapter) {
300         Object JavaDoc result= Platform.getAdapterManager().getAdapter(this, adapter);
301         if (result != null)
302             return result;
303         if (fParent != null)
304             return fParent.getAdapter(adapter);
305         return null;
306     }
307 }
308
Popular Tags