]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/ExtractInterfaceProcessor.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / structure / ExtractInterfaceProcessor.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 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.corext.refactoring.structure;
12
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Comparator;
17 import java.util.HashMap;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23
24 import org.eclipse.core.runtime.Assert;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.NullProgressMonitor;
28 import org.eclipse.core.runtime.OperationCanceledException;
29 import org.eclipse.core.runtime.SubProgressMonitor;
30
31 import org.eclipse.core.resources.IFile;
32
33 import org.eclipse.core.filebuffers.ITextFileBuffer;
34
35 import org.eclipse.text.edits.MalformedTreeException;
36 import org.eclipse.text.edits.TextEdit;
37
38 import org.eclipse.jface.text.BadLocationException;
39 import org.eclipse.jface.text.Document;
40 import org.eclipse.jface.text.IDocument;
41
42 import org.eclipse.ltk.core.refactoring.Change;
43 import org.eclipse.ltk.core.refactoring.GroupCategory;
44 import org.eclipse.ltk.core.refactoring.GroupCategorySet;
45 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
46 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
47 import org.eclipse.ltk.core.refactoring.TextChange;
48 import org.eclipse.ltk.core.refactoring.TextEditBasedChange;
49 import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
50 import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
51 import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
52
53 import org.eclipse.jdt.core.ICompilationUnit;
54 import org.eclipse.jdt.core.IField;
55 import org.eclipse.jdt.core.IJavaElement;
56 import org.eclipse.jdt.core.IJavaProject;
57 import org.eclipse.jdt.core.IMember;
58 import org.eclipse.jdt.core.IMethod;
59 import org.eclipse.jdt.core.IPackageFragment;
60 import org.eclipse.jdt.core.IType;
61 import org.eclipse.jdt.core.ITypeParameter;
62 import org.eclipse.jdt.core.JavaCore;
63 import org.eclipse.jdt.core.JavaModelException;
64 import org.eclipse.jdt.core.dom.AST;
65 import org.eclipse.jdt.core.dom.ASTNode;
66 import org.eclipse.jdt.core.dom.ASTParser;
67 import org.eclipse.jdt.core.dom.ASTRequestor;
68 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
69 import org.eclipse.jdt.core.dom.Annotation;
70 import org.eclipse.jdt.core.dom.CompilationUnit;
71 import org.eclipse.jdt.core.dom.EnumDeclaration;
72 import org.eclipse.jdt.core.dom.FieldDeclaration;
73 import org.eclipse.jdt.core.dom.IBinding;
74 import org.eclipse.jdt.core.dom.IExtendedModifier;
75 import org.eclipse.jdt.core.dom.IMethodBinding;
76 import org.eclipse.jdt.core.dom.ITypeBinding;
77 import org.eclipse.jdt.core.dom.IVariableBinding;
78 import org.eclipse.jdt.core.dom.MethodDeclaration;
79 import org.eclipse.jdt.core.dom.Modifier;
80 import org.eclipse.jdt.core.dom.NodeFinder;
81 import org.eclipse.jdt.core.dom.ParameterizedType;
82 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
83 import org.eclipse.jdt.core.dom.Type;
84 import org.eclipse.jdt.core.dom.TypeDeclaration;
85 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
86 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
87 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
88 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
89 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
90 import org.eclipse.jdt.core.refactoring.descriptors.ExtractInterfaceDescriptor;
91 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
92
93 import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
94 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
95 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
96 import org.eclipse.jdt.internal.corext.dom.Bindings;
97 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
98 import org.eclipse.jdt.internal.corext.refactoring.Checks;
99 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
100 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
101 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
102 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
103 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
104 import org.eclipse.jdt.internal.corext.refactoring.changes.CreateCompilationUnitChange;
105 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
106 import org.eclipse.jdt.internal.corext.refactoring.reorg.ASTNodeDeleteUtil;
107 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel;
108 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsSolver;
109 import org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor;
110 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompilationUnitRange;
111 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
112 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ISourceConstraintVariable;
113 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ITypeConstraintVariable;
114 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
115 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers;
116 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
117 import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
118 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
119 import org.eclipse.jdt.internal.corext.util.JdtFlags;
120 import org.eclipse.jdt.internal.corext.util.Messages;
121 import org.eclipse.jdt.internal.corext.util.Strings;
122
123 import org.eclipse.jdt.ui.CodeGeneration;
124 import org.eclipse.jdt.ui.JavaElementLabels;
125
126 import org.eclipse.jdt.internal.ui.JavaPlugin;
127 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
128 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
129 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
130
131
132 /**
133  * Refactoring processor to extract interfaces.
134  */
135 public final class ExtractInterfaceProcessor extends SuperTypeRefactoringProcessor {
136
137         private static final String ATTRIBUTE_ABSTRACT= "abstract"; //$NON-NLS-1$
138
139         private static final String ATTRIBUTE_COMMENTS= "comments"; //$NON-NLS-1$
140
141         private static final String ATTRIBUTE_PUBLIC= "public"; //$NON-NLS-1$
142
143         /** The identifier of this processor */
144         public static final String IDENTIFIER= "org.eclipse.jdt.ui.extractInterfaceProcessor"; //$NON-NLS-1$
145
146         /** The extract interface group category set */
147         private static final GroupCategorySet SET_EXTRACT_INTERFACE= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.extractInterface", //$NON-NLS-1$
148                         RefactoringCoreMessages.ExtractInterfaceProcessor_category_name, RefactoringCoreMessages.ExtractInterfaceProcessor_category_description));
149
150         /**
151          * Is the specified member extractable from the type?
152          *
153          * @param member
154          *            the member to test
155          * @return <code>true</code> if the member is extractable,
156          *         <code>false</code> otherwise
157          * @throws JavaModelException
158          *             if an error occurs
159          */
160         protected static boolean isExtractableMember(final IMember member) throws JavaModelException {
161                 Assert.isNotNull(member);
162                 switch (member.getElementType()) {
163                         case IJavaElement.METHOD:
164                                 return JdtFlags.isPublic(member) && !JdtFlags.isStatic(member) && !((IMethod) member).isConstructor();
165                         case IJavaElement.FIELD:
166                                 return JdtFlags.isPublic(member) && JdtFlags.isStatic(member) && JdtFlags.isFinal(member) && !JdtFlags.isEnum(member);
167                         default:
168                                 return false;
169                 }
170         }
171
172         /** Should extracted methods be declared as abstract? */
173         private boolean fAbstract= true;
174
175         /** Should override annotations be generated? */
176         private boolean fAnnotations= false;
177
178         /** The text edit based change manager */
179         private TextEditBasedChangeManager fChangeManager= null;
180
181         /** Should comments be generated? */
182         private boolean fComments= true;
183
184         /** The members to extract */
185         private IMember[] fMembers= null;
186
187         /** Should extracted methods be declared as public? */
188         private boolean fPublic= true;
189
190         /** The subtype where to extract the supertype */
191         private IType fSubType;
192
193         /** The supertype name */
194         private String fSuperName;
195
196         /** The source of the new supertype */
197         private String fSuperSource= null;
198
199         /**
200          * Creates a new extract interface processor.
201          *
202          * @param type
203          *            the type where to extract the supertype, or <code>null</code>
204          *            if invoked by scripting
205          * @param settings
206          *            the code generation settings, or <code>null</code> if
207          *            invoked by scripting
208          */
209         public ExtractInterfaceProcessor(final IType type, final CodeGenerationSettings settings) {
210                 super(settings);
211                 fSubType= type;
212                 if (fSubType != null)
213                         fSuperName= fSubType.getElementName();
214         }
215
216         /**
217          * Creates a new extract interface processor from refactoring arguments.
218          *
219          * @param arguments
220          *            the refactoring arguments
221          * @param status
222          *            the resulting status
223          */
224         public ExtractInterfaceProcessor(JavaRefactoringArguments arguments, RefactoringStatus status) {
225                 super(null);
226                 RefactoringStatus initializeStatus= initialize(arguments);
227                 status.merge(initializeStatus);
228         }
229
230         /*
231          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor,org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext)
232          */
233         @Override
234         public final RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, final CheckConditionsContext context) throws CoreException, OperationCanceledException {
235                 Assert.isNotNull(monitor);
236                 Assert.isNotNull(context);
237                 final RefactoringStatus status= new RefactoringStatus();
238                 fChangeManager= new TextEditBasedChangeManager();
239                 try {
240                         monitor.beginTask("", 1); //$NON-NLS-1$
241                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_checking);
242                         status.merge(Checks.checkIfCuBroken(fSubType));
243                         if (!status.hasError()) {
244                                 if (fSubType.isBinary() || fSubType.isReadOnly() || !fSubType.exists())
245                                         status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_no_binary, JavaStatusContext.create(fSubType)));
246                                 else if (fSubType.isAnonymous())
247                                         status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_no_anonymous, JavaStatusContext.create(fSubType)));
248                                 else if (fSubType.isAnnotation())
249                                         status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_no_annotation, JavaStatusContext.create(fSubType)));
250                                 else {
251                                         status.merge(checkSuperType());
252                                         if (!status.hasFatalError()) {
253                                                 if (!status.hasFatalError()) {
254                                                         fChangeManager= createChangeManager(new SubProgressMonitor(monitor, 1), status);
255                                                         if (!status.hasFatalError()) {
256                                                                 Checks.addModifiedFilesToChecker(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()), context);
257                                                         }
258                                                 }
259                                         }
260                                 }
261                         }
262                 } finally {
263                         monitor.done();
264                 }
265                 return status;
266         }
267
268         /*
269          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
270          */
271         @Override
272         public final RefactoringStatus checkInitialConditions(final IProgressMonitor monitor) throws CoreException, OperationCanceledException {
273                 Assert.isNotNull(monitor);
274                 final RefactoringStatus status= new RefactoringStatus();
275                 try {
276                         monitor.beginTask("", 1); //$NON-NLS-1$
277                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_checking);
278                         status.merge(Checks.checkIfCuBroken(fSubType));
279                         monitor.worked(1);
280                 } finally {
281                         monitor.done();
282                 }
283                 return status;
284         }
285
286         /**
287          * Checks whether the supertype clashes with existing types.
288          *
289          * @return the status of the condition checking
290          * @throws JavaModelException
291          *             if an error occurs
292          */
293         protected final RefactoringStatus checkSuperType() throws JavaModelException {
294                 final IPackageFragment fragment= fSubType.getPackageFragment();
295                 final IType type= Checks.findTypeInPackage(fragment, fSuperName);
296                 if (type != null && type.exists()) {
297                         if (fragment.isDefaultPackage())
298                                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_default_type, BasicElementLabels.getJavaElementName(fSuperName)));
299                         else {
300                                 String packageLabel= JavaElementLabels.getElementLabel(fragment, JavaElementLabels.ALL_DEFAULT);
301                                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_type, new String[] { BasicElementLabels.getJavaElementName(fSuperName), packageLabel }));
302                         }
303                 }
304                 return new RefactoringStatus();
305         }
306
307         /**
308          * Checks whether the type name is valid.
309          *
310          * @param name
311          *            the name to check
312          * @return the status of the condition checking
313          */
314         public final RefactoringStatus checkTypeName(final String name) {
315                 Assert.isNotNull(name);
316                 try {
317                         final RefactoringStatus result= Checks.checkTypeName(name, fSubType);
318                         if (result.hasFatalError())
319                                 return result;
320                         final String unitName= JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), name);
321                         result.merge(Checks.checkCompilationUnitName(unitName, fSubType));
322                         if (result.hasFatalError())
323                                 return result;
324                         final IPackageFragment fragment= fSubType.getPackageFragment();
325                         if (fragment.getCompilationUnit(unitName).exists()) {
326                                 result.addFatalError(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_existing_compilation_unit, new String[] { BasicElementLabels.getResourceName(unitName), JavaElementLabels.getElementLabel(fragment, JavaElementLabels.ALL_DEFAULT) }));
327                                 return result;
328                         }
329                         result.merge(checkSuperType());
330                         return result;
331                 } catch (JavaModelException exception) {
332                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error);
333                 }
334         }
335
336         /*
337          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#createChange(org.eclipse.core.runtime.IProgressMonitor)
338          */
339         @Override
340         public final Change createChange(final IProgressMonitor monitor) throws CoreException, OperationCanceledException {
341                 Assert.isNotNull(monitor);
342                 try {
343                         monitor.beginTask("", 1); //$NON-NLS-1$
344                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
345                         final Map<String, String> arguments= new HashMap<String, String>();
346                         String project= null;
347                         final IJavaProject javaProject= fSubType.getJavaProject();
348                         if (javaProject != null)
349                                 project= javaProject.getElementName();
350                         int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
351                         try {
352                                 if (fSubType.isLocal() || fSubType.isAnonymous())
353                                         flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
354                         } catch (JavaModelException exception) {
355                                 JavaPlugin.log(exception);
356                         }
357                         final IPackageFragment fragment= fSubType.getPackageFragment();
358                         final ICompilationUnit cu= fragment.getCompilationUnit(JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), fSuperName));
359                         final IType type= cu.getType(fSuperName);
360                         final String description= Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_description_descriptor_short, BasicElementLabels.getJavaElementName(fSuperName));
361                         final String header= Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_descriptor_description, new String[] { JavaElementLabels.getElementLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(fSubType, JavaElementLabels.ALL_FULLY_QUALIFIED) });
362                         final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
363                         comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractInterfaceProcessor_refactored_element_pattern, JavaElementLabels.getElementLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED)));
364                         final String[] settings= new String[fMembers.length];
365                         for (int index= 0; index < settings.length; index++)
366                                 settings[index]= JavaElementLabels.getElementLabel(fMembers[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
367                         comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.ExtractInterfaceProcessor_extracted_members_pattern, settings));
368                         addSuperTypeSettings(comment, true);
369                         final ExtractInterfaceDescriptor descriptor= RefactoringSignatureDescriptorFactory.createExtractInterfaceDescriptor(project, description, comment.asString(), arguments, flags);
370                         arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fSubType));
371                         arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, fSuperName);
372                         for (int index= 0; index < fMembers.length; index++)
373                                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (index + 1), JavaRefactoringDescriptorUtil.elementToHandle(project, fMembers[index]));
374                         arguments.put(ATTRIBUTE_ABSTRACT, Boolean.valueOf(fAbstract).toString());
375                         arguments.put(ATTRIBUTE_COMMENTS, Boolean.valueOf(fComments).toString());
376                         arguments.put(ATTRIBUTE_PUBLIC, Boolean.valueOf(fPublic).toString());
377                         arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplace).toString());
378                         arguments.put(ATTRIBUTE_INSTANCEOF, Boolean.valueOf(fInstanceOf).toString());
379                         final DynamicValidationRefactoringChange change= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.ExtractInterfaceRefactoring_name, fChangeManager.getAllChanges());
380                         final IFile file= ResourceUtil.getFile(fSubType.getCompilationUnit());
381                         if (fSuperSource != null && fSuperSource.length() > 0)
382                                 change.add(new CreateCompilationUnitChange(fSubType.getPackageFragment().getCompilationUnit(JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), fSuperName)), fSuperSource, file.getCharset(false)));
383                         monitor.worked(1);
384                         return change;
385                 } finally {
386                         monitor.done();
387                 }
388         }
389
390         /**
391          * Creates the text change manager for this processor.
392          *
393          * @param monitor
394          *            the progress monitor to display progress
395          * @param status
396          *            the refactoring status
397          * @return the created text change manager
398          * @throws JavaModelException
399          *             if the method declaration could not be found
400          * @throws CoreException
401          *             if the changes could not be generated
402          */
403         protected final TextEditBasedChangeManager createChangeManager(final IProgressMonitor monitor, final RefactoringStatus status) throws JavaModelException, CoreException {
404                 Assert.isNotNull(status);
405                 Assert.isNotNull(monitor);
406                 try {
407                         monitor.beginTask("", 300); //$NON-NLS-1$
408                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
409                         resetEnvironment();
410                         final TextEditBasedChangeManager manager= new TextEditBasedChangeManager();
411                         final CompilationUnitRewrite sourceRewrite= new CompilationUnitRewrite(fSubType.getCompilationUnit());
412                         final AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(fSubType, sourceRewrite.getRoot());
413                         if (declaration != null) {
414                                 createTypeSignature(sourceRewrite, declaration, status, new SubProgressMonitor(monitor, 20));
415                                 final IField[] fields= getExtractedFields(fSubType.getCompilationUnit());
416                                 if (fields.length > 0)
417                                         ASTNodeDeleteUtil.markAsDeleted(fields, sourceRewrite, sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_remove_field_label, SET_EXTRACT_INTERFACE));
418                                 if (fSubType.isInterface()) {
419                                         final IMethod[] methods= getExtractedMethods(fSubType.getCompilationUnit());
420                                         if (methods.length > 0)
421                                                 ASTNodeDeleteUtil.markAsDeleted(methods, sourceRewrite, sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_remove_method_label, SET_EXTRACT_INTERFACE));
422                                 }
423                                 final String name= JavaModelUtil.getRenamedCUName(fSubType.getCompilationUnit(), fSuperName);
424                                 final ICompilationUnit original= fSubType.getPackageFragment().getCompilationUnit(name);
425                                 final ICompilationUnit copy= getSharedWorkingCopy(original.getPrimary(), new SubProgressMonitor(monitor, 20));
426                                 fSuperSource= createTypeSource(copy, fSubType, fSuperName, sourceRewrite, declaration, status, new SubProgressMonitor(monitor, 40));
427                                 if (fSuperSource != null) {
428                                         copy.getBuffer().setContents(fSuperSource);
429                                         JavaModelUtil.reconcile(copy);
430                                 }
431                                 final Set<String> replacements= new HashSet<String>();
432                                 if (fReplace)
433                                         rewriteTypeOccurrences(manager, sourceRewrite, copy, replacements, status, new SubProgressMonitor(monitor, 220));
434                                 createMethodComments(sourceRewrite, replacements);
435                                 manager.manage(fSubType.getCompilationUnit(), sourceRewrite.createChange(true));
436                         }
437                         return manager;
438                 } finally {
439                         monitor.done();
440                 }
441         }
442
443         /*
444          * @see org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeRefactoringProcessor#createContraintSolver(org.eclipse.jdt.internal.corext.refactoring.structure.constraints.SuperTypeConstraintsModel)
445          */
446         @Override
447         protected final SuperTypeConstraintsSolver createContraintSolver(final SuperTypeConstraintsModel model) {
448                 return new ExtractInterfaceConstraintsSolver(model, fSuperName);
449         }
450
451         /**
452          * Creates a target field declaration.
453          *
454          * @param sourceRewrite
455          *            the source compilation unit rewrite
456          * @param targetRewrite
457          *            the target rewrite
458          * @param targetDeclaration
459          *            the target type declaration
460          * @param fragment
461          *            the source variable declaration fragment
462          * @throws CoreException
463          *             if a buffer could not be retrieved
464          */
465         protected final void createFieldDeclaration(final CompilationUnitRewrite sourceRewrite, final ASTRewrite targetRewrite, final AbstractTypeDeclaration targetDeclaration, final VariableDeclarationFragment fragment) throws CoreException {
466                 Assert.isNotNull(targetDeclaration);
467                 Assert.isNotNull(sourceRewrite);
468                 Assert.isNotNull(targetRewrite);
469                 Assert.isNotNull(fragment);
470                 final FieldDeclaration field= (FieldDeclaration) fragment.getParent();
471                 ImportRewriteUtil.collectImports(fSubType.getJavaProject(), field, fTypeBindings, fStaticBindings, false);
472                 final ASTRewrite rewrite= ASTRewrite.create(field.getAST());
473                 final ITrackedNodePosition position= rewrite.track(field);
474                 final ListRewrite rewriter= rewrite.getListRewrite(field, FieldDeclaration.FRAGMENTS_PROPERTY);
475                 VariableDeclarationFragment current= null;
476                 for (final Iterator<VariableDeclarationFragment> iterator= field.fragments().iterator(); iterator.hasNext();) {
477                         current= iterator.next();
478                         if (!current.getName().getIdentifier().equals(fragment.getName().getIdentifier()))
479                                 rewriter.remove(current, null);
480                 }
481                 final ICompilationUnit unit= sourceRewrite.getCu();
482                 final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(unit);
483                 try {
484                         final IDocument document= new Document(buffer.getDocument().get());
485                         try {
486                                 rewrite.rewriteAST(document, unit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
487                                 targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.FIELD_DECLARATION), null);
488                         } catch (MalformedTreeException exception) {
489                                 JavaPlugin.log(exception);
490                         } catch (BadLocationException exception) {
491                                 JavaPlugin.log(exception);
492                         }
493                 } finally {
494                         RefactoringFileBuffers.release(unit);
495                 }
496         }
497
498         /**
499          * {@inheritDoc}
500          */
501         @Override
502         protected final void createMemberDeclarations(final CompilationUnitRewrite sourceRewrite, final ASTRewrite targetRewrite, final AbstractTypeDeclaration targetDeclaration) throws CoreException {
503                 Assert.isNotNull(sourceRewrite);
504                 Assert.isNotNull(targetRewrite);
505                 Assert.isNotNull(targetDeclaration);
506                 Arrays.sort(fMembers, new Comparator<IMember>() {
507
508                         public final int compare(final IMember first, final IMember second) {
509                                 try {
510                                         return first.getSourceRange().getOffset() - second.getSourceRange().getOffset();
511                                 } catch (JavaModelException exception) {
512                                         return first.hashCode() - second.hashCode();
513                                 }
514                         }
515                 });
516                 fTypeBindings.clear();
517                 fStaticBindings.clear();
518                 if (fMembers.length > 0) {
519                         IMember member= null;
520                         for (int index= fMembers.length - 1; index >= 0; index--) {
521                                 member= fMembers[index];
522                                 if (member instanceof IField) {
523                                         createFieldDeclaration(sourceRewrite, targetRewrite, targetDeclaration, ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) member, sourceRewrite.getRoot()));
524                                 } else if (member instanceof IMethod) {
525                                         createMethodDeclaration(sourceRewrite, targetRewrite, targetDeclaration, ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) member, sourceRewrite.getRoot()));
526                                 }
527                         }
528                 }
529         }
530
531         /**
532          * Creates the method comment for the specified declaration.
533          *
534          * @param sourceRewrite
535          *            the compilation unit rewrite
536          * @param declaration
537          *            the method declaration
538          * @param replacements
539          *            the set of variable binding keys of formal parameters which
540          *            must be replaced
541          * @param javadoc
542          *            <code>true</code> if javadoc comments are processed,
543          *            <code>false</code> otherwise
544          * @throws CoreException
545          *             if an error occurs
546          */
547         protected final void createMethodComment(final CompilationUnitRewrite sourceRewrite, final MethodDeclaration declaration, final Set<String> replacements, final boolean javadoc) throws CoreException {
548                 Assert.isNotNull(sourceRewrite);
549                 Assert.isNotNull(declaration);
550                 Assert.isNotNull(replacements);
551                 final IMethodBinding binding= declaration.resolveBinding();
552                 if (binding != null) {
553                         IVariableBinding variable= null;
554                         SingleVariableDeclaration argument= null;
555                         final IPackageFragment fragment= fSubType.getPackageFragment();
556                         final String string= fragment.isDefaultPackage() ? fSuperName : fragment.getElementName() + "." + fSuperName; //$NON-NLS-1$
557                         final ITypeBinding[] bindings= binding.getParameterTypes();
558                         final String[] names= new String[bindings.length];
559                         for (int offset= 0; offset < names.length; offset++) {
560                                 argument= (SingleVariableDeclaration) declaration.parameters().get(offset);
561                                 variable= argument.resolveBinding();
562                                 if (variable != null) {
563                                         if (replacements.contains(variable.getKey()))
564                                                 names[offset]= string;
565                                         else {
566                                                 if (binding.isVarargs() && bindings[offset].isArray() && offset == names.length - 1)
567                                                         names[offset]= Bindings.getFullyQualifiedName(bindings[offset].getElementType());
568                                                 else
569                                                         names[offset]= Bindings.getFullyQualifiedName(bindings[offset]);
570                                         }
571                                 }
572                         }
573                         final String comment= CodeGeneration.getMethodComment(fSubType.getCompilationUnit(), fSubType.getElementName(), declaration, false, binding.getName(), string, names, StubUtility.getLineDelimiterUsed(fSubType.getJavaProject()));
574                         if (comment != null) {
575                                 final ASTRewrite rewrite= sourceRewrite.getASTRewrite();
576                                 if (declaration.getJavadoc() != null) {
577                                         rewrite.replace(declaration.getJavadoc(), rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC), sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_rewrite_comment, SET_EXTRACT_INTERFACE));
578                                 } else if (javadoc) {
579                                         rewrite.set(declaration, MethodDeclaration.JAVADOC_PROPERTY, rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC), sourceRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_comment, SET_EXTRACT_INTERFACE));
580                                 }
581                         }
582                 }
583         }
584
585         /**
586          * Creates the method annotations and comments of the extracted methods in
587          * the source type.
588          *
589          * @param sourceRewrite
590          *            the source compilation unit rewrite
591          * @param replacements
592          *            the set of variable binding keys of formal parameters which
593          *            must be replaced
594          * @throws CoreException
595          *             if an error occurs
596          */
597         protected final void createMethodComments(final CompilationUnitRewrite sourceRewrite, final Set<String> replacements) throws CoreException {
598                 Assert.isNotNull(sourceRewrite);
599                 Assert.isNotNull(replacements);
600                 if (fMembers.length > 0 && (fAnnotations || fComments)) {
601                         IJavaProject project= fSubType.getJavaProject();
602                         boolean annotations= fAnnotations && !JavaModelUtil.isVersionLessThan(project.getOption(JavaCore.COMPILER_SOURCE, true), JavaCore.VERSION_1_6);
603                         boolean javadoc= project.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true).equals(JavaCore.ENABLED);
604                         IMember member= null;
605                         for (int index= 0; index < fMembers.length; index++) {
606                                 member= fMembers[index];
607                                 if (member instanceof IMethod) {
608                                         MethodDeclaration declaration= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) member, sourceRewrite.getRoot());
609                                         if (annotations) {
610                                                 ASTRewrite rewrite= sourceRewrite.getASTRewrite();
611                                                 AST ast= rewrite.getAST();
612                                                 Annotation marker= ast.newMarkerAnnotation();
613                                                 marker.setTypeName(ast.newSimpleName("Override")); //$NON-NLS-1$
614                                                 rewrite.getListRewrite(declaration, MethodDeclaration.MODIFIERS2_PROPERTY).insertFirst(marker, null);
615                                         }
616                                         if (fComments)
617                                                 createMethodComment(sourceRewrite, declaration, replacements, javadoc);
618                                 }
619                         }
620                 }
621         }
622
623         /**
624          * Creates a target method declaration.
625          *
626          * @param sourceRewrite
627          *            the source compilation unit rewrite
628          * @param targetRewrite
629          *            the target rewrite
630          * @param targetDeclaration
631          *            the target type declaration
632          * @param declaration
633          *            the source method declaration
634          * @throws CoreException
635          *             if a buffer could not be retrieved
636          */
637         protected final void createMethodDeclaration(final CompilationUnitRewrite sourceRewrite, final ASTRewrite targetRewrite, final AbstractTypeDeclaration targetDeclaration, final MethodDeclaration declaration) throws CoreException {
638                 Assert.isNotNull(targetDeclaration);
639                 Assert.isNotNull(sourceRewrite);
640                 Assert.isNotNull(targetRewrite);
641                 Assert.isNotNull(declaration);
642                 ImportRewriteUtil.collectImports(fSubType.getJavaProject(), declaration, fTypeBindings, fStaticBindings, true);
643                 ASTRewrite rewrite= ASTRewrite.create(declaration.getAST());
644                 ITrackedNodePosition position= rewrite.track(declaration);
645                 if (declaration.getBody() != null)
646                         rewrite.remove(declaration.getBody(), null);
647                 ListRewrite list= rewrite.getListRewrite(declaration, declaration.getModifiersProperty());
648                 boolean publicFound= false;
649                 boolean abstractFound= false;
650                 Annotation annotation= null;
651                 for (IExtendedModifier extended : (List<IExtendedModifier>) declaration.modifiers()) {
652                         if (!extended.isAnnotation()) {
653                                 Modifier modifier= (Modifier) extended;
654                                 if (fPublic && modifier.getKeyword().equals(Modifier.ModifierKeyword.PUBLIC_KEYWORD)) {
655                                         publicFound= true;
656                                         continue;
657                                 }
658                                 if (fAbstract && modifier.getKeyword().equals(Modifier.ModifierKeyword.ABSTRACT_KEYWORD)) {
659                                         abstractFound= true;
660                                         continue;
661                                 }
662                                 list.remove(modifier, null);
663                         } else if (extended.isAnnotation()) {
664                                 annotation= (Annotation) extended;
665                                 ITypeBinding binding= annotation.resolveTypeBinding();
666                                 if (binding.getQualifiedName().equals("java.lang.Override") || ! Bindings.isClassOrRuntimeAnnotation(binding)) //$NON-NLS-1$
667                                         list.remove(annotation, null);
668                         }
669                 }
670                 ModifierRewrite rewriter= ModifierRewrite.create(rewrite, declaration);
671                 if (fPublic && !publicFound)
672                         rewriter.setVisibility(Modifier.PUBLIC, null);
673                 if (fAbstract && !abstractFound)
674                         rewriter.setModifiers(Modifier.ABSTRACT, 0, null);
675                 
676                 for (SingleVariableDeclaration param : (List<SingleVariableDeclaration>) declaration.parameters()) {
677                         ListRewrite modifierRewrite= rewrite.getListRewrite(param, SingleVariableDeclaration.MODIFIERS2_PROPERTY);
678                         for (IExtendedModifier extended : (List<IExtendedModifier>) param.modifiers()) {
679                                 if (!extended.isAnnotation()) {
680                                         Modifier modifier= (Modifier) extended;
681                                         modifierRewrite.remove(modifier, null);
682                                 } else if (extended.isAnnotation()) {
683                                         annotation= (Annotation) extended;
684                                         ITypeBinding binding= annotation.resolveTypeBinding();
685                                         if (! Bindings.isClassOrRuntimeAnnotation(binding))
686                                                 modifierRewrite.remove(annotation, null);
687                                 }
688                         }
689                 }
690                 
691                 ICompilationUnit unit= sourceRewrite.getCu();
692                 ITextFileBuffer buffer= RefactoringFileBuffers.acquire(unit);
693                 try {
694                         IDocument document= new Document(buffer.getDocument().get());
695                         try {
696                                 rewrite.rewriteAST(document, unit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
697                                 targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.METHOD_DECLARATION), null);
698                         } catch (MalformedTreeException exception) {
699                                 JavaPlugin.log(exception);
700                         } catch (BadLocationException exception) {
701                                 JavaPlugin.log(exception);
702                         }
703                 } finally {
704                         RefactoringFileBuffers.release(unit);
705                 }
706         }
707
708         /**
709          * Creates the new signature of the source type.
710          *
711          * @param rewrite
712          *            the source compilation unit rewrite
713          * @param declaration
714          *            the type declaration
715          * @param status
716          *            the refactoring status
717          * @param monitor
718          *            the progress monitor to use
719          * @throws JavaModelException
720          *             if the type parameters cannot be retrieved
721          */
722         protected final void createTypeSignature(final CompilationUnitRewrite rewrite, final AbstractTypeDeclaration declaration, final RefactoringStatus status, final IProgressMonitor monitor) throws JavaModelException {
723                 Assert.isNotNull(rewrite);
724                 Assert.isNotNull(declaration);
725                 Assert.isNotNull(status);
726                 Assert.isNotNull(monitor);
727                 try {
728                         monitor.beginTask("", 1); //$NON-NLS-1$
729                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
730                         final AST ast= declaration.getAST();
731                         final ITypeParameter[] parameters= fSubType.getTypeParameters();
732                         Type type= ast.newSimpleType(ast.newSimpleName(fSuperName));
733                         if (parameters.length > 0) {
734                                 final ParameterizedType parameterized= ast.newParameterizedType(type);
735                                 for (int index= 0; index < parameters.length; index++)
736                                         parameterized.typeArguments().add(ast.newSimpleType(ast.newSimpleName(parameters[index].getElementName())));
737                                 type= parameterized;
738                         }
739                         final ASTRewrite rewriter= rewrite.getASTRewrite();
740                         if (declaration instanceof TypeDeclaration)
741                                 rewriter.getListRewrite(declaration, TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY).insertLast(type, rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_super_interface, SET_EXTRACT_INTERFACE));
742                         else if (declaration instanceof EnumDeclaration)
743                                 rewriter.getListRewrite(declaration, EnumDeclaration.SUPER_INTERFACE_TYPES_PROPERTY).insertLast(type, rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.ExtractInterfaceProcessor_add_super_interface, SET_EXTRACT_INTERFACE));
744                         monitor.worked(1);
745                 } finally {
746                         monitor.done();
747                 }
748         }
749
750         /**
751          * Should extracted methods be declared as abstract?
752          *
753          * @return <code>true</code> if the should be declared as abstract,
754          *         <code>false</code> otherwise
755          */
756         public final boolean getAbstract() {
757                 return fAbstract;
758         }
759
760         /*
761          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getElements()
762          */
763         @Override
764         public final Object[] getElements() {
765                 return new Object[] { fSubType };
766         }
767
768         /**
769          * Returns the list of extractable members from the type.
770          *
771          * @return the list of extractable members
772          * @throws JavaModelException
773          *             if an error occurs
774          */
775         public final IMember[] getExtractableMembers() throws JavaModelException {
776                 final List<IJavaElement> list= new ArrayList<IJavaElement>();
777                 IJavaElement[] children= fSubType.getChildren();
778                 for (int index= 0; index < children.length; index++) {
779                         if (children[index] instanceof IMember && isExtractableMember((IMember) children[index]))
780                                 list.add(children[index]);
781                 }
782                 final IMember[] members= new IMember[list.size()];
783                 list.toArray(members);
784                 return members;
785         }
786
787         /**
788          * Returns the extracted fields from the compilation unit.
789          *
790          * @param unit
791          *            the compilation unit
792          * @return the extracted fields
793          */
794         protected final IField[] getExtractedFields(final ICompilationUnit unit) {
795                 Assert.isNotNull(unit);
796                 final List<IJavaElement> list= new ArrayList<IJavaElement>();
797                 for (int index= 0; index < fMembers.length; index++) {
798                         if (fMembers[index] instanceof IField) {
799                                 final IJavaElement element= JavaModelUtil.findInCompilationUnit(unit, fMembers[index]);
800                                 if (element instanceof IField)
801                                         list.add(element);
802                         }
803                 }
804                 final IField[] fields= new IField[list.size()];
805                 list.toArray(fields);
806                 return fields;
807         }
808
809         /**
810          * Returns the extracted methods from the compilation unit.
811          *
812          * @param unit
813          *            the compilation unit
814          * @return the extracted methods
815          */
816         protected final IMethod[] getExtractedMethods(final ICompilationUnit unit) {
817                 Assert.isNotNull(unit);
818                 final List<IJavaElement> list= new ArrayList<IJavaElement>();
819                 for (int index= 0; index < fMembers.length; index++) {
820                         if (fMembers[index] instanceof IMethod) {
821                                 final IJavaElement element= JavaModelUtil.findInCompilationUnit(unit, fMembers[index]);
822                                 if (element instanceof IMethod)
823                                         list.add(element);
824                         }
825                 }
826                 final IMethod[] methods= new IMethod[list.size()];
827                 list.toArray(methods);
828                 return methods;
829         }
830
831         /*
832          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getIdentifier()
833          */
834         @Override
835         public final String getIdentifier() {
836                 return IDENTIFIER;
837         }
838
839         /*
840          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getProcessorName()
841          */
842         @Override
843         public final String getProcessorName() {
844                 return RefactoringCoreMessages.ExtractInterfaceProcessor_name;
845         }
846
847         /**
848          * Should extracted methods be declared as public?
849          *
850          * @return <code>true</code> if the should be declared as public,
851          *         <code>false</code> otherwise
852          */
853         public final boolean getPublic() {
854                 return fPublic;
855         }
856
857         /**
858          * Returns the type where to extract an interface.
859          *
860          * @return the type where to extract an interface
861          */
862         public final IType getType() {
863                 return fSubType;
864         }
865
866         /**
867          * Returns the new interface name.
868          *
869          * @return the new interface name
870          */
871         public final String getTypeName() {
872                 return fSuperName;
873         }
874
875         /**
876          * Should override annotations be generated?
877          * 
878          * @return <code>true</code> if annotations should be generated, <code>false</code> otherwise
879          */
880         public final boolean isAnnotations() {
881                 return fAnnotations;
882         }
883
884         private RefactoringStatus initialize(JavaRefactoringArguments extended) {
885                 String handle= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
886                 if (handle != null) {
887                         final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false);
888                         if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE)
889                                 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_INTERFACE);
890                         else
891                                 fSubType= (IType) element;
892                 } else
893                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
894                 final String name= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
895                 if (name != null) {
896                         fSuperName= name;
897                         final RefactoringStatus status= checkTypeName(name);
898                         if (status.hasError())
899                                 return status;
900                 } else
901                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
902                 final String deferred= extended.getAttribute(ATTRIBUTE_ABSTRACT);
903                 if (deferred != null) {
904                         fAbstract= Boolean.valueOf(deferred).booleanValue();
905                 } else
906                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_ABSTRACT));
907                 final String comment= extended.getAttribute(ATTRIBUTE_COMMENTS);
908                 if (comment != null) {
909                         fComments= Boolean.valueOf(comment).booleanValue();
910                 } else
911                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_COMMENTS));
912                 final String instance= extended.getAttribute(ATTRIBUTE_INSTANCEOF);
913                 if (instance != null) {
914                         fInstanceOf= Boolean.valueOf(instance).booleanValue();
915                 } else
916                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_INSTANCEOF));
917                 final String visibility= extended.getAttribute(ATTRIBUTE_PUBLIC);
918                 if (visibility != null) {
919                         fPublic= Boolean.valueOf(visibility).booleanValue();
920                 } else
921                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_PUBLIC));
922                 final String replace= extended.getAttribute(ATTRIBUTE_REPLACE);
923                 if (replace != null) {
924                         fReplace= Boolean.valueOf(replace).booleanValue();
925                 } else
926                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
927                 int count= 1;
928                 final List<IJavaElement> elements= new ArrayList<IJavaElement>();
929                 String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
930                 final RefactoringStatus status= new RefactoringStatus();
931                 while ((handle= extended.getAttribute(attribute)) != null) {
932                         final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false);
933                         if (element == null || !element.exists())
934                                 status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.EXTRACT_INTERFACE));
935                         else
936                                 elements.add(element);
937                         count++;
938                         attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
939                 }
940                 fMembers= elements.toArray(new IMember[elements.size()]);
941                 fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fSubType.getJavaProject());
942                 if (!status.isOK())
943                         return status;
944                 return new RefactoringStatus();
945         }
946
947         /*
948          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#isApplicable()
949          */
950         @Override
951         public final boolean isApplicable() throws CoreException {
952                 return Checks.isAvailable(fSubType) && !fSubType.isBinary() && !fSubType.isReadOnly() && !fSubType.isAnnotation() && !fSubType.isAnonymous();
953         }
954
955         /**
956          * Should comments be generated?
957          *
958          * @return <code>true</code> if comments should be generated,
959          *         <code>false</code> otherwise
960          */
961         public final boolean isComments() {
962                 return fComments;
963         }
964
965         /*
966          * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#loadParticipants(org.eclipse.ltk.core.refactoring.RefactoringStatus,org.eclipse.ltk.core.refactoring.participants.SharableParticipants)
967          */
968         @Override
969         public final RefactoringParticipant[] loadParticipants(final RefactoringStatus status, final SharableParticipants sharedParticipants) throws CoreException {
970                 return new RefactoringParticipant[0];
971         }
972
973         /**
974          * Normalizes the indentation of the specified text.
975          *
976          * @param code
977          *            the text to normalize
978          * @return the normalized text
979          * @throws JavaModelException
980          *             if an error occurs
981          */
982         protected final String normalizeText(final String code) throws JavaModelException {
983                 Assert.isNotNull(code);
984                 final String[] lines= Strings.convertIntoLines(code);
985                 final IJavaProject project= fSubType.getJavaProject();
986                 Strings.trimIndentation(lines, project, false);
987                 return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(project));
988         }
989
990         /**
991          * Resets the environment.
992          */
993         protected void resetEnvironment() {
994                 fSuperSource= null;
995                 resetWorkingCopies();
996         }
997
998         /**
999          * {@inheritDoc}
1000          */
1001         @Override
1002         protected final void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final ICompilationUnit unit, final CompilationUnit node, final Set<String> replacements, final IProgressMonitor monitor) throws CoreException {
1003                 try {
1004                         monitor.beginTask("", 100); //$NON-NLS-1$
1005                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1006                         CompilationUnitRewrite currentRewrite= null;
1007                         final boolean isSubUnit= rewrite.getCu().equals(unit.getPrimary());
1008                         if (isSubUnit)
1009                                 currentRewrite= rewrite;
1010                         else
1011                                 currentRewrite= new CompilationUnitRewrite(unit, node);
1012                         final Collection<ITypeConstraintVariable> collection= fTypeOccurrences.get(unit);
1013                         if (collection != null && !collection.isEmpty()) {
1014                                 final IProgressMonitor subMonitor= new SubProgressMonitor(monitor, 100);
1015                                 try {
1016                                         subMonitor.beginTask("", collection.size() * 10); //$NON-NLS-1$
1017                                         subMonitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1018                                         TType estimate= null;
1019                                         ISourceConstraintVariable variable= null;
1020                                         ITypeConstraintVariable constraint= null;
1021                                         for (final Iterator<ITypeConstraintVariable> iterator= collection.iterator(); iterator.hasNext();) {
1022                                                 variable= iterator.next();
1023                                                 if (variable instanceof ITypeConstraintVariable) {
1024                                                         constraint= (ITypeConstraintVariable) variable;
1025                                                         estimate= (TType) constraint.getData(SuperTypeConstraintsSolver.DATA_TYPE_ESTIMATE);
1026                                                         if (estimate != null) {
1027                                                                 final CompilationUnitRange range= constraint.getRange();
1028                                                                 if (isSubUnit)
1029                                                                         rewriteTypeOccurrence(range, estimate, requestor, currentRewrite, node, replacements, currentRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.SuperTypeRefactoringProcessor_update_type_occurrence, SET_SUPER_TYPE));
1030                                                                 else {
1031                                                                         final ASTNode result= NodeFinder.perform(node, range.getSourceRange());
1032                                                                         if (result != null)
1033                                                                                 rewriteTypeOccurrence(estimate, currentRewrite, result, currentRewrite.createCategorizedGroupDescription(RefactoringCoreMessages.SuperTypeRefactoringProcessor_update_type_occurrence, SET_SUPER_TYPE));
1034                                                                 }
1035                                                                 subMonitor.worked(10);
1036                                                         }
1037                                                 }
1038                                         }
1039                                 } finally {
1040                                         subMonitor.done();
1041                                 }
1042                         }
1043                         if (!isSubUnit) {
1044                                 final TextChange change= currentRewrite.createChange(true);
1045                                 if (change != null)
1046                                         manager.manage(unit, change);
1047                         }
1048                 } finally {
1049                         monitor.done();
1050                 }
1051         }
1052
1053         /**
1054          * Creates the necessary text edits to replace the subtype occurrences by a
1055          * supertype.
1056          *
1057          * @param manager
1058          *            the text change manager
1059          * @param sourceRewrite
1060          *            the compilation unit of the subtype (not in working copy mode)
1061          * @param superUnit
1062          *            the compilation unit of the supertype (in working copy mode)
1063          * @param replacements
1064          *            the set of variable binding keys of formal parameters which
1065          *            must be replaced
1066          * @param status
1067          *            the refactoring status
1068          * @param monitor
1069          *            the progress monitor to display progress
1070          * @throws CoreException
1071          *             if an error occurs
1072          */
1073         protected final void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final CompilationUnitRewrite sourceRewrite, final ICompilationUnit superUnit, final Set<String> replacements, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
1074                 Assert.isNotNull(manager);
1075                 Assert.isNotNull(sourceRewrite);
1076                 Assert.isNotNull(superUnit);
1077                 Assert.isNotNull(replacements);
1078                 Assert.isNotNull(status);
1079                 Assert.isNotNull(monitor);
1080                 try {
1081                         monitor.beginTask("", 300); //$NON-NLS-1$
1082                         monitor.setTaskName(RefactoringCoreMessages.ExtractInterfaceProcessor_creating);
1083                         final ICompilationUnit subUnit= getSharedWorkingCopy(fSubType.getCompilationUnit().getPrimary(), new SubProgressMonitor(monitor, 20));
1084                         final ITextFileBuffer buffer= RefactoringFileBuffers.acquire(fSubType.getCompilationUnit());
1085                         final ASTRewrite rewrite= sourceRewrite.getASTRewrite();
1086                         try {
1087                                 final IDocument document= new Document(buffer.getDocument().get());
1088                                 try {
1089                                         rewrite.rewriteAST(document, fSubType.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
1090                                 } catch (MalformedTreeException exception) {
1091                                         JavaPlugin.log(exception);
1092                                 } catch (BadLocationException exception) {
1093                                         JavaPlugin.log(exception);
1094                                 }
1095                                 subUnit.getBuffer().setContents(document.get());
1096                         } finally {
1097                                 RefactoringFileBuffers.release(fSubType.getCompilationUnit());
1098                         }
1099                         JavaModelUtil.reconcile(subUnit);
1100                         final IJavaProject project= subUnit.getJavaProject();
1101                         final ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
1102                         parser.setWorkingCopyOwner(fOwner);
1103                         parser.setResolveBindings(true);
1104                         parser.setProject(project);
1105                         parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
1106                         parser.createASTs(new ICompilationUnit[] { subUnit}, new String[0], new ASTRequestor() {
1107
1108                                 @Override
1109                                 public final void acceptAST(final ICompilationUnit unit, final CompilationUnit node) {
1110                                         try {
1111                                                 final IType subType= (IType) JavaModelUtil.findInCompilationUnit(unit, fSubType);
1112                                                 final AbstractTypeDeclaration subDeclaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(subType, node);
1113                                                 if (subDeclaration != null) {
1114                                                         final ITypeBinding subBinding= subDeclaration.resolveBinding();
1115                                                         if (subBinding != null) {
1116                                                                 String name= null;
1117                                                                 ITypeBinding superBinding= null;
1118                                                                 final ITypeBinding[] superBindings= subBinding.getInterfaces();
1119                                                                 for (int index= 0; index < superBindings.length; index++) {
1120                                                                         name= superBindings[index].getName();
1121                                                                         if (name.startsWith(fSuperName) && superBindings[index].getTypeArguments().length == subBinding.getTypeParameters().length)
1122                                                                                 superBinding= superBindings[index];
1123                                                                 }
1124                                                                 if (superBinding != null) {
1125                                                                         solveSuperTypeConstraints(unit, node, subType, subBinding, superBinding, new SubProgressMonitor(monitor, 80), status);
1126                                                                         if (!status.hasFatalError()) {
1127                                                                                 rewriteTypeOccurrences(manager, this, sourceRewrite, unit, node, replacements, status, new SubProgressMonitor(monitor, 200));
1128                                                                                 if (manager.containsChangesIn(superUnit)) {
1129                                                                                         final TextEditBasedChange change= manager.get(superUnit);
1130                                                                                         if (change instanceof TextChange) {
1131                                                                                                 final TextEdit edit= ((TextChange) change).getEdit();
1132                                                                                                 if (edit != null) {
1133                                                                                                         final IDocument document= new Document(superUnit.getBuffer().getContents());
1134                                                                                                         try {
1135                                                                                                                 edit.apply(document, TextEdit.UPDATE_REGIONS);
1136                                                                                                         } catch (MalformedTreeException exception) {
1137                                                                                                                 JavaPlugin.log(exception);
1138                                                                                                                 status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
1139                                                                                                         } catch (BadLocationException exception) {
1140                                                                                                                 JavaPlugin.log(exception);
1141                                                                                                                 status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
1142                                                                                                         }
1143                                                                                                         fSuperSource= document.get();
1144                                                                                                         manager.remove(superUnit);
1145                                                                                                 }
1146                                                                                         }
1147                                                                                 }
1148                                                                         }
1149                                                                 }
1150                                                         }
1151                                                 }
1152                                         } catch (JavaModelException exception) {
1153                                                 JavaPlugin.log(exception);
1154                                                 status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractInterfaceProcessor_internal_error));
1155                                         }
1156                                 }
1157
1158                                 @Override
1159                                 public final void acceptBinding(final String key, final IBinding binding) {
1160                                         // Do nothing
1161                                 }
1162                         }, new NullProgressMonitor());
1163                 } finally {
1164                         monitor.done();
1165                 }
1166         }
1167
1168         /**
1169          * Determines whether extracted methods should be declared as abstract.
1170          *
1171          * @param declare
1172          *            <code>true</code> to declare them public, <code>false</code>
1173          *            otherwise
1174          */
1175         public final void setAbstract(final boolean declare) {
1176                 fAbstract= declare;
1177         }
1178
1179         /**
1180          * Determines whether override annotations should be generated.
1181          * 
1182          * @param annotations <code>true</code> to generate override annotations, <code>false</code> otherwise
1183          */
1184         public final void setAnnotations(final boolean annotations) {
1185                 fAnnotations= annotations;
1186         }
1187
1188         /**
1189          * Determines whether comments should be generated.
1190          *
1191          * @param comments
1192          *            <code>true</code> to generate comments, <code>false</code>
1193          *            otherwise
1194          */
1195         public final void setComments(final boolean comments) {
1196                 fComments= comments;
1197         }
1198
1199         /**
1200          * Sets the members to be extracted.
1201          *
1202          * @param members
1203          *            the members to be extracted
1204          * @throws JavaModelException
1205          *             if an error occurs
1206          */
1207         public final void setExtractedMembers(final IMember[] members) throws JavaModelException {
1208                 fMembers= members;
1209         }
1210
1211         /**
1212          * Determines whether extracted methods should be declared as public.
1213          *
1214          * @param declare
1215          *            <code>true</code> to declare them public, <code>false</code>
1216          *            otherwise
1217          */
1218         public final void setPublic(final boolean declare) {
1219                 fPublic= declare;
1220         }
1221
1222         /**
1223          * Sets the new interface name.
1224          *
1225          * @param name
1226          *            the new interface name
1227          */
1228         public final void setTypeName(final String name) {
1229                 Assert.isNotNull(name);
1230                 fSuperName= name;
1231         }
1232 }