KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.HashMap JavaDoc;
14 import java.util.Map JavaDoc;
15
16 import org.eclipse.core.runtime.IStatus;
17 import org.eclipse.jdt.core.*;
18
19 /**
20  * This class is used to perform operations on multiple <code>IJavaElement</code>.
21  * It is responible for running each operation in turn, collecting
22  * the errors and merging the corresponding <code>JavaElementDelta</code>s.
23  * <p>
24  * If several errors occured, they are collected in a multi-status
25  * <code>JavaModelStatus</code>. Otherwise, a simple <code>JavaModelStatus</code>
26  * is thrown.
27  */

28 public abstract class MultiOperation extends JavaModelOperation {
29     /**
30      * Table specifying insertion positions for elements being
31      * copied/moved/renamed. Keyed by elements being processed, and
32      * values are the corresponding insertion point.
33      * @see #processElements()
34      */

35     protected Map JavaDoc insertBeforeElements = new HashMap JavaDoc(1);
36     /**
37      * Table specifying the new parent for elements being
38      * copied/moved/renamed.
39      * Keyed by elements being processed, and
40      * values are the corresponding destination parent.
41      */

42     protected Map JavaDoc newParents;
43     /**
44      * This table presents the data in <code>fRenamingList</code> in a more
45      * convenient way.
46      */

47     protected Map JavaDoc renamings;
48     /**
49      * The list of renamings supplied to the operation
50      */

51     protected String JavaDoc[] renamingsList = null;
52     /**
53      * Creates a new <code>MultiOperation</code> on <code>elementsToProcess</code>.
54      */

55     protected MultiOperation(IJavaElement[] elementsToProcess, boolean force) {
56         super(elementsToProcess, force);
57     }
58     /**
59      * Creates a new <code>MultiOperation</code>.
60      */

61     protected MultiOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements, boolean force) {
62         super(elementsToProcess, parentElements, force);
63         this.newParents = new HashMap JavaDoc(elementsToProcess.length);
64         if (elementsToProcess.length == parentElements.length) {
65             for (int i = 0; i < elementsToProcess.length; i++) {
66                 this.newParents.put(elementsToProcess[i], parentElements[i]);
67             }
68         } else { //same destination for all elements to be moved/copied/renamed
69
for (int i = 0; i < elementsToProcess.length; i++) {
70                 this.newParents.put(elementsToProcess[i], parentElements[0]);
71             }
72         }
73     
74     }
75     /**
76      * Convenience method to create a <code>JavaModelException</code>
77      * embending a <code>JavaModelStatus</code>.
78      */

79     protected void error(int code, IJavaElement element) throws JavaModelException {
80         throw new JavaModelException(new JavaModelStatus(code, element));
81     }
82     /**
83      * Executes the operation.
84      *
85      * @exception JavaModelException if one or several errors occured during the operation.
86      * If multiple errors occured, the corresponding <code>JavaModelStatus</code> is a
87      * multi-status. Otherwise, it is a simple one.
88      */

89     protected void executeOperation() throws JavaModelException {
90         processElements();
91     }
92     /**
93      * Returns the parent of the element being copied/moved/renamed.
94      */

95     protected IJavaElement getDestinationParent(IJavaElement child) {
96         return (IJavaElement)this.newParents.get(child);
97     }
98     /**
99      * Returns the name to be used by the progress monitor.
100      */

101     protected abstract String JavaDoc getMainTaskName();
102     /**
103      * Returns the new name for <code>element</code>, or <code>null</code>
104      * if there are no renamings specified.
105      */

106     protected String JavaDoc getNewNameFor(IJavaElement element) throws JavaModelException {
107         String JavaDoc newName = null;
108         if (this.renamings != null)
109             newName = (String JavaDoc) this.renamings.get(element);
110         if (newName == null && element instanceof IMethod && ((IMethod) element).isConstructor())
111             newName = getDestinationParent(element).getElementName();
112         return newName;
113     }
114     /**
115      * Sets up the renamings hashtable - keys are the elements and
116      * values are the new name.
117      */

118     private void initializeRenamings() {
119         if (this.renamingsList != null && this.renamingsList.length == this.elementsToProcess.length) {
120             this.renamings = new HashMap JavaDoc(this.renamingsList.length);
121             for (int i = 0; i < this.renamingsList.length; i++) {
122                 if (this.renamingsList[i] != null) {
123                     this.renamings.put(this.elementsToProcess[i], this.renamingsList[i]);
124                 }
125             }
126         }
127     }
128     /**
129      * Returns <code>true</code> if this operation represents a move or rename, <code>false</code>
130      * if this operation represents a copy.<br>
131      * Note: a rename is just a move within the same parent with a name change.
132      */

133     protected boolean isMove() {
134         return false;
135     }
136     /**
137      * Returns <code>true</code> if this operation represents a rename, <code>false</code>
138      * if this operation represents a copy or move.
139      */

140     protected boolean isRename() {
141         return false;
142     }
143     
144     /**
145      * Subclasses must implement this method to process a given <code>IJavaElement</code>.
146      */

147     protected abstract void processElement(IJavaElement element) throws JavaModelException;
148     /**
149      * Processes all the <code>IJavaElement</code>s in turn, collecting errors
150      * and updating the progress monitor.
151      *
152      * @exception JavaModelException if one or several operation(s) was unable to
153      * be completed.
154      */

155     protected void processElements() throws JavaModelException {
156         try {
157             beginTask(getMainTaskName(), this.elementsToProcess.length);
158             IJavaModelStatus[] errors = new IJavaModelStatus[3];
159             int errorsCounter = 0;
160             for (int i = 0; i < this.elementsToProcess.length; i++) {
161                 try {
162                     verify(this.elementsToProcess[i]);
163                     processElement(this.elementsToProcess[i]);
164                 } catch (JavaModelException jme) {
165                     if (errorsCounter == errors.length) {
166                         // resize
167
System.arraycopy(errors, 0, (errors = new IJavaModelStatus[errorsCounter*2]), 0, errorsCounter);
168                     }
169                     errors[errorsCounter++] = jme.getJavaModelStatus();
170                 } finally {
171                     worked(1);
172                 }
173             }
174             if (errorsCounter == 1) {
175                 throw new JavaModelException(errors[0]);
176             } else if (errorsCounter > 1) {
177                 if (errorsCounter != errors.length) {
178                     // resize
179
System.arraycopy(errors, 0, (errors = new IJavaModelStatus[errorsCounter]), 0, errorsCounter);
180                 }
181                 throw new JavaModelException(JavaModelStatus.newMultiStatus(errors));
182             }
183         } finally {
184             done();
185         }
186     }
187     /**
188      * Sets the insertion position in the new container for the modified element. The element
189      * being modified will be inserted before the specified new sibling. The given sibling
190      * must be a child of the destination container specified for the modified element.
191      * The default is <code>null</code>, which indicates that the element is to be
192      * inserted at the end of the container.
193      */

194     public void setInsertBefore(IJavaElement modifiedElement, IJavaElement newSibling) {
195         this.insertBeforeElements.put(modifiedElement, newSibling);
196     }
197     /**
198      * Sets the new names to use for each element being copied. The renamings
199      * correspond to the elements being processed, and the number of
200      * renamings must match the number of elements being processed.
201      * A <code>null</code> entry in the list indicates that an element
202      * is not to be renamed.
203      *
204      * <p>Note that some renamings may not be used. If both a parent
205      * and a child have been selected for copy/move, only the parent
206      * is changed. Therefore, if a new name is specified for the child,
207      * the child's name will not be changed.
208      */

209     public void setRenamings(String JavaDoc[] renamingsList) {
210         this.renamingsList = renamingsList;
211         initializeRenamings();
212     }
213     /**
214      * This method is called for each <code>IJavaElement</code> before
215      * <code>processElement</code>. It should check that this <code>element</code>
216      * can be processed.
217      */

218     protected abstract void verify(IJavaElement element) throws JavaModelException;
219     /**
220      * Verifies that the <code>destination</code> specified for the <code>element</code> is valid for the types of the
221      * <code>element</code> and <code>destination</code>.
222      */

223     protected void verifyDestination(IJavaElement element, IJavaElement destination) throws JavaModelException {
224         if (destination == null || !destination.exists())
225             error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, destination);
226         
227         int destType = destination.getElementType();
228         switch (element.getElementType()) {
229             case IJavaElement.PACKAGE_DECLARATION :
230             case IJavaElement.IMPORT_DECLARATION :
231                 if (destType != IJavaElement.COMPILATION_UNIT)
232                     error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
233                 break;
234             case IJavaElement.TYPE :
235                 if (destType != IJavaElement.COMPILATION_UNIT && destType != IJavaElement.TYPE)
236                     error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
237                 break;
238             case IJavaElement.METHOD :
239             case IJavaElement.FIELD :
240             case IJavaElement.INITIALIZER :
241                 if (destType != IJavaElement.TYPE || destination instanceof BinaryType)
242                     error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
243                 break;
244             case IJavaElement.COMPILATION_UNIT :
245                 if (destType != IJavaElement.PACKAGE_FRAGMENT)
246                     error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
247                 else {
248                     CompilationUnit cu = (CompilationUnit)element;
249                     if (isMove() && cu.isWorkingCopy() && !cu.isPrimary())
250                         error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
251                 }
252                 break;
253             case IJavaElement.PACKAGE_FRAGMENT :
254                 IPackageFragment fragment = (IPackageFragment) element;
255                 IJavaElement parent = fragment.getParent();
256                 if (parent.isReadOnly())
257                     error(IJavaModelStatusConstants.READ_ONLY, element);
258                 else if (destType != IJavaElement.PACKAGE_FRAGMENT_ROOT)
259                     error(IJavaModelStatusConstants.INVALID_DESTINATION, element);
260                 break;
261             default :
262                 error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
263         }
264     }
265     /**
266      * Verify that the new name specified for <code>element</code> is
267      * valid for that type of Java element.
268      */

269     protected void verifyRenaming(IJavaElement element) throws JavaModelException {
270         String JavaDoc newName = getNewNameFor(element);
271         boolean isValid = true;
272         IJavaProject project = element.getJavaProject();
273         String JavaDoc sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
274         String JavaDoc complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
275         switch (element.getElementType()) {
276             case IJavaElement.PACKAGE_FRAGMENT :
277                 if (((IPackageFragment) element).isDefaultPackage()) {
278                     // don't allow renaming of default package (see PR #1G47GUM)
279
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, element));
280                 }
281                 isValid = JavaConventions.validatePackageName(newName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
282                 break;
283             case IJavaElement.COMPILATION_UNIT :
284                 isValid = JavaConventions.validateCompilationUnitName(newName,sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
285                 break;
286             case IJavaElement.INITIALIZER :
287                 isValid = false; //cannot rename initializers
288
break;
289             default :
290                 isValid = JavaConventions.validateIdentifier(newName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR;
291                 break;
292         }
293     
294         if (!isValid) {
295             throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INVALID_NAME, element, newName));
296         }
297     }
298     /**
299      * Verifies that the positioning sibling specified for the <code>element</code> is exists and
300      * its parent is the destination container of this <code>element</code>.
301      */

302     protected void verifySibling(IJavaElement element, IJavaElement destination) throws JavaModelException {
303         IJavaElement insertBeforeElement = (IJavaElement) this.insertBeforeElements.get(element);
304         if (insertBeforeElement != null) {
305             if (!insertBeforeElement.exists() || !insertBeforeElement.getParent().equals(destination)) {
306                 error(IJavaModelStatusConstants.INVALID_SIBLING, insertBeforeElement);
307             }
308         }
309     }
310 }
311
Popular Tags