blob: 850fca6abb82c3e1a5b2d6d66dc442ba5c1fd375 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.refactoring.java.plugins;
import com.sun.source.util.TreePath;
import java.io.IOException;
import java.util.*;
import javax.lang.model.element.*;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.TreePathHandle;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.ProgressEvent;
import org.netbeans.modules.refactoring.api.ProgressListener;
import org.netbeans.modules.refactoring.java.api.EncapsulateFieldRefactoring;
import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils;
import org.netbeans.modules.refactoring.java.plugins.EncapsulateFieldRefactoringPlugin.EncapsulateDesc;
import org.netbeans.modules.refactoring.java.plugins.EncapsulateFieldRefactoringPlugin.Encapsulator;
import org.netbeans.modules.refactoring.java.spi.JavaRefactoringPlugin;
import org.netbeans.modules.refactoring.java.ui.EncapsulateFieldPanel.Javadoc;
import org.netbeans.modules.refactoring.java.ui.EncapsulateFieldPanel.SortBy;
import org.netbeans.modules.refactoring.java.ui.EncapsulateFieldsRefactoring;
import org.netbeans.modules.refactoring.java.ui.EncapsulateFieldsRefactoring.EncapsulateFieldInfo;
import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
import org.openide.filesystems.FileObject;
import org.openide.util.NbBundle;
/** Encapsulate fields refactoring. This is a composed refactoring (uses instances of {@link org.netbeans.modules.refactoring.api.EncapsulateFieldRefactoring}
* to encapsulate several fields at once.
*
* @author Pavel Flaska
* @author Jan Becicka
* @author Jan Pokorsky
*/
public final class EncapsulateFieldsPlugin extends JavaRefactoringPlugin {
private List<EncapsulateFieldRefactoringPlugin> refactorings;
private final EncapsulateFieldsRefactoring refactoring;
private ProgressListener listener = new ProgressListener() {
@Override
public void start(ProgressEvent event) {
fireProgressListenerStart(event.getOperationType(),event.getCount());
}
@Override
public void step(ProgressEvent event) {
fireProgressListenerStep();
}
@Override
public void stop(ProgressEvent event) {
fireProgressListenerStop();
}
};
/** Creates a new instance of EcapsulateFields.
* @param selectedObjects Array of objects (fields) that should be encapsulated.
*/
public EncapsulateFieldsPlugin(EncapsulateFieldsRefactoring refactoring) {
this.refactoring = refactoring;
}
@Override
protected Problem checkParameters(CompilationController javac) throws IOException {
return validation(2, javac);
}
@Override
public Problem fastCheckParameters() {
Collection<EncapsulateFieldInfo> fields = refactoring.getRefactorFields();
if (fields.isEmpty()) {
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "ERR_EncapsulateNothingSelected"));
}
initRefactorings(fields,
refactoring.getMethodModifiers(),
refactoring.getFieldModifiers(),
refactoring.isAlwaysUseAccessors(),
refactoring.isGeneratePropertyChangeSupport(),
refactoring.isGenerateVetoableSupport());
try {
return validation(1, null);
} catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
@Override
protected Problem preCheck(CompilationController javac) throws IOException {
javac.toPhase(JavaSource.Phase.RESOLVED);
Problem preCheckProblem;
preCheckProblem = isElementAvail(refactoring.getSelectedObject(), javac);
if (preCheckProblem != null) {
return preCheckProblem;
}
TreePath selectedField = refactoring.getSelectedObject().resolve(javac);
if (selectedField == null) {
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "DSC_ElNotAvail"));
}
Element elm = javac.getTrees().getElement(selectedField);
if (elm != null && ElementKind.FIELD == elm.getKind()) {
preCheckProblem = JavaPluginUtils.isSourceElement(elm, javac);
if (preCheckProblem != null) {
return preCheckProblem;
}
TreePath source = javac.getTrees().getPath(elm);
if (source == null) {
// missing sources with field declaration
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "DSC_ElNotAvail"));
}
TypeElement encloser = (TypeElement) elm.getEnclosingElement();
if (ElementKind.INTERFACE == encloser.getKind() || NestingKind.ANONYMOUS == encloser.getNestingKind()) {
// interface constants, local variables and annonymous declarations are unsupported
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "ERR_EncapsulateInIntf"));
}
return null;
}
TreePath clazz = JavaRefactoringUtils.findEnclosingClass(javac, selectedField, true, false, true, false, false);
TypeElement clazzElm = (TypeElement) javac.getTrees().getElement(clazz);
preCheckProblem = JavaPluginUtils.isSourceElement(clazzElm, javac);
if (preCheckProblem != null) {
return preCheckProblem;
}
if (elm != clazzElm || clazzElm == null) {
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "ERR_EncapsulateWrongType"));
}
if (ElementKind.INTERFACE == clazzElm.getKind()
|| ElementKind.ANNOTATION_TYPE == clazzElm.getKind()
|| NestingKind.ANONYMOUS == clazzElm.getNestingKind()) {
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "ERR_EncapsulateInIntf"));
}
for (Element member : clazzElm.getEnclosedElements()) {
if (ElementKind.FIELD == member.getKind()) { // no enum constant
return null;
}
}
return new Problem(true, NbBundle.getMessage(EncapsulateFieldsPlugin.class, "ERR_EncapsulateNoFields", clazzElm.getQualifiedName()));
}
@Override
public Problem prepare(RefactoringElementsBag elements) {
Problem problem = null;
Set<FileObject> references = new LinkedHashSet<FileObject>();
List<EncapsulateDesc> descs = new ArrayList<EncapsulateDesc>(refactorings.size());
fireProgressListenerStart(AbstractRefactoring.PREPARE, refactorings.size() + 1);
for (EncapsulateFieldRefactoringPlugin ref : refactorings) {
if (cancelRequested.get()) {
return null;
}
EncapsulateDesc desc = ref.prepareEncapsulator(problem);
problem = desc.p;
desc.p = null;
if (problem != null && problem.isFatal()) {
return problem;
}
descs.add(desc);
references.addAll(desc.refs);
fireProgressListenerStep();
}
Encapsulator encapsulator = new Encapsulator(descs, problem,
refactoring.getContext().lookup(Integer.class),
refactoring.getContext().lookup(SortBy.class),
refactoring.getContext().lookup(Javadoc.class)
);
Problem prob = createAndAddElements(references, new TransformTask(encapsulator, descs.get(0).fieldHandle), elements, refactoring);
fireProgressListenerStop();
problem = encapsulator.getProblem();
return prob != null ? prob : problem;
}
private void initRefactorings(Collection<EncapsulateFieldInfo> refactorFields, Set<Modifier> methodModifier, Set<Modifier> fieldModifier, boolean alwaysUseAccessors, boolean pcs, boolean vcs) {
refactorings = new ArrayList<EncapsulateFieldRefactoringPlugin>(refactorFields.size());
for (EncapsulateFieldInfo info: refactorFields) {
EncapsulateFieldRefactoring ref = new EncapsulateFieldRefactoring(info.getField());
ref.setGetterName(info.getGetterName());
ref.setSetterName(info.getSetterName());
ref.setMethodModifiers(methodModifier);
ref.setFieldModifiers(fieldModifier);
ref.setAlwaysUseAccessors(alwaysUseAccessors);
ref.setGeneratePropertyChangeSupport(pcs);
ref.setGenerateVetoableSupport(vcs);
refactorings.add(new EncapsulateFieldRefactoringPlugin(ref));
}
}
private Problem validation(int phase, CompilationController javac) throws IOException {
Problem result = null;
for (EncapsulateFieldRefactoringPlugin ref : refactorings) {
Problem lastresult = null;
switch (phase) {
case 1: lastresult = ref.fastCheckParameters(); break;
case 2:
lastresult = ref.preCheck(javac);
result = JavaPluginUtils.chainProblems(result, lastresult);
if (result != null && result.isFatal()) {
return result;
}
lastresult = ref.checkParameters(javac);
ref.addProgressListener(listener);
break;
}
result = JavaPluginUtils.chainProblems(result, lastresult);
if (result != null && result.isFatal()) {
return result;
}
}
return result;
}
@Override
protected JavaSource getJavaSource(Phase p) {
TreePathHandle selectedField = refactoring.getSelectedObject();
FileObject fo = selectedField.getFileObject();
return JavaSource.forFileObject(fo);
}
}