001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.refactoring.java.plugins;
042:
043: import java.io.IOException;
044: import java.util.*;
045: import java.util.Set;
046: import javax.lang.model.element.*;
047: import org.netbeans.api.java.source.*;
048: import org.netbeans.modules.refactoring.api.Problem;
049: import org.netbeans.modules.refactoring.api.ProgressEvent;
050: import org.netbeans.modules.refactoring.java.RetoucheUtils;
051: import org.netbeans.modules.refactoring.java.api.InnerToOuterRefactoring;
052: import org.netbeans.modules.refactoring.java.spi.JavaRefactoringPlugin;
053: import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
054: import org.openide.filesystems.FileObject;
055: import org.openide.util.NbBundle;
056: import org.openide.util.Utilities;
057:
058: /** Plugin that implements the core functionality of "inner to outer" refactoring.
059: *
060: * @author Martin Matula
061: * @author Jan Becicka
062: */
063: public class InnerToOuterRefactoringPlugin extends
064: JavaRefactoringPlugin {
065: /** Reference to the parent refactoring instance */
066: private final InnerToOuterRefactoring refactoring;
067: private TreePathHandle treePathHandle;
068:
069: /** Creates a new instance of InnerToOuterRefactoringPlugin
070: * @param refactoring Parent refactoring instance.
071: */
072: InnerToOuterRefactoringPlugin(InnerToOuterRefactoring refactoring) {
073: this .refactoring = refactoring;
074: this .treePathHandle = refactoring.getRefactoringSource()
075: .lookup(TreePathHandle.class);
076: }
077:
078: protected JavaSource getJavaSource(Phase p) {
079: switch (p) {
080: case PRECHECK:
081: ClasspathInfo cpInfo = getClasspathInfo(refactoring);
082: return JavaSource.create(cpInfo, treePathHandle
083: .getFileObject());
084: default:
085: return JavaSource.forFileObject(treePathHandle
086: .getFileObject());
087: }
088: }
089:
090: @Override
091: protected Problem preCheck(CompilationController info)
092: throws IOException {
093: // fire operation start on the registered progress listeners (4 steps)
094: fireProgressListenerStart(refactoring.PRE_CHECK, 4);
095: Problem preCheckProblem = null;
096: info.toPhase(JavaSource.Phase.RESOLVED);
097: Element el = treePathHandle.resolveElement(info);
098: TreePathHandle sourceType = refactoring.getSourceType();
099:
100: if (sourceType == null) {
101: preCheckProblem = new Problem(true, NbBundle.getMessage(
102: InnerToOuterRefactoringPlugin.class,
103: "ERR_InnerToOuter_MustBeInnerClass")); // NOI18N
104: return preCheckProblem;
105: }
106:
107: // check whether the element is valid
108: // Problem result = isElementAvail(sourceType);
109: // if (result != null) {
110: // // fatal error -> don't continue with further checks
111: // return result;
112: // }
113: if (!RetoucheUtils.isElementInOpenProject(RetoucheUtils
114: .getFileObject(sourceType))) {
115: preCheckProblem = new Problem(true, NbBundle.getMessage(
116: InnerToOuterRefactoringPlugin.class,
117: "ERR_ProjectNotOpened"));
118: return preCheckProblem;
119: }
120:
121: // // check whether the element is an unresolved class
122: // if (sourceType instanceof UnresolvedClass) {
123: // // fatal error -> return
124: // return new Problem(true, NbBundle.getMessage(InnerToOuterRefactoringPlugin.class, "ERR_ElementNotAvailable")); // NOI18N
125: // }
126:
127: refactoring.setClassName(RetoucheUtils
128: .getSimpleName(sourceType));
129:
130: // increase progress (step 1)
131: fireProgressListenerStep();
132:
133: // #1 - check if the class is an inner class
134: // RefObject declCls = (RefObject) sourceType.refImmediateComposite();
135: if (el instanceof TypeElement) {
136: if (((TypeElement) el).getNestingKind() == NestingKind.ANONYMOUS) {
137: // fatal error -> return
138: preCheckProblem = new Problem(true, NbBundle
139: .getMessage(
140: InnerToOuterRefactoringPlugin.class,
141: "ERR_InnerToOuter_Anonymous")); // NOI18N
142: return preCheckProblem;
143: }
144: if (!((TypeElement) el).getNestingKind().isNested()) {
145: // fatal error -> return
146: preCheckProblem = new Problem(true, NbBundle
147: .getMessage(
148: InnerToOuterRefactoringPlugin.class,
149: "ERR_InnerToOuter_MustBeInnerClass")); // NOI18N
150: return preCheckProblem;
151: }
152: } else {
153: preCheckProblem = new Problem(true, NbBundle.getMessage(
154: InnerToOuterRefactoringPlugin.class,
155: "ERR_InnerToOuter_MustBeInnerClass")); // NOI18N
156: return preCheckProblem;
157: }
158:
159: // increase progress (step 2)
160: fireProgressListenerStep();
161:
162: // if (Modifier.isStatic(sourceType.getModifiers())) {
163: // fireProgressListenerStep();
164: // } else {
165: // // collect all features of the outer class
166: // Set featureSet = new HashSet(), innerFeatures = new HashSet();
167: // getFeatureSet((JavaClass) declCls, featureSet, new HashSet());
168: // getFeatureSet(sourceType, innerFeatures, new HashSet());
169: // featureSet.remove(sourceType);
170: //
171: // // increase progress (step 3)
172: // fireProgressListenerStep();
173: //
174: // // check if any features of the outer class are referenced
175: // // if so, create refactoring elements for them
176: // multipartIds = new ArrayList();
177: // Collection outerReferences = traverseForOuterReferences(sourceType, new ArrayList(), multipartIds, featureSet, innerFeatures, (JavaClass) declCls);
178: // if (!outerReferences.isEmpty()) {
179: // this.outerReferences = outerReferences;
180: refactoring.setReferenceName("outer"); // NOI18N
181: // }
182: // }
183:
184: fireProgressListenerStop();
185: return preCheckProblem;
186: }
187:
188: @Override
189: public Problem checkParameters() {
190: //TODO:
191: return null;
192: }
193:
194: @Override
195: public Problem fastCheckParameters() {
196: Problem result = null;
197:
198: String newName = refactoring.getClassName();
199:
200: if (!Utilities.isJavaIdentifier(newName)) {
201: result = createProblem(result, true, NbBundle.getMessage(
202: InnerToOuterRefactoringPlugin.class,
203: "ERR_InvalidIdentifier", newName)); // NOI18N
204: return result;
205: }
206:
207: FileObject primFile = refactoring.getSourceType()
208: .getFileObject();
209: FileObject folder = primFile.getParent();
210: FileObject[] children = folder.getChildren();
211: for (FileObject child : children) {
212: if (!child.isVirtual() && child.getName().equals(newName)
213: && "java".equals(child.getExt())) { // NOI18N
214: result = createProblem(result, true, NbBundle
215: .getMessage(
216: InnerToOuterRefactoringPlugin.class,
217: "ERR_ClassClash", newName, folder
218: .getName())); // NOI18N
219: return result;
220: }
221: }
222:
223: return null;
224: }
225:
226: private Set<FileObject> getRelevantFiles() {
227: ClasspathInfo cpInfo = getClasspathInfo(refactoring);
228: HashSet<FileObject> set = new HashSet<FileObject>();
229: ClassIndex idx = cpInfo.getClassIndex();
230: set.addAll(idx.getResources(RetoucheUtils
231: .getElementHandle(refactoring.getSourceType()), EnumSet
232: .of(ClassIndex.SearchKind.TYPE_REFERENCES,
233: ClassIndex.SearchKind.IMPLEMENTORS), EnumSet
234: .of(ClassIndex.SearchScope.SOURCE)));
235: return set;
236: }
237:
238: public Problem prepare(RefactoringElementsBag refactoringElements) {
239: Set<FileObject> a = getRelevantFiles();
240: fireProgressListenerStart(ProgressEvent.START, a.size());
241: final InnerToOuterTransformer innerToOuter = new InnerToOuterTransformer(
242: refactoring);
243: TransformTask transform = new TransformTask(innerToOuter,
244: refactoring.getSourceType());
245: createAndAddElements(a, transform, refactoringElements,
246: refactoring);
247: fireProgressListenerStop();
248: return innerToOuter.getProblem();
249: }
250: }
|