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.api;
042:
043: import java.io.IOException;
044: import java.util.Collection;
045: import java.util.Comparator;
046: import java.util.Iterator;
047: import java.util.TreeSet;
048: import javax.lang.model.element.TypeElement;
049: import javax.lang.model.type.TypeMirror;
050: import javax.lang.model.util.Types;
051: import org.netbeans.api.java.source.CancellableTask;
052: import org.netbeans.api.java.source.CompilationController;
053: import org.netbeans.api.java.source.ElementHandle;
054: import org.netbeans.api.java.source.JavaSource;
055: import org.netbeans.api.java.source.JavaSource.Phase;
056: import org.netbeans.api.java.source.TreePathHandle;
057: import org.netbeans.modules.refactoring.api.AbstractRefactoring;
058: import org.openide.util.lookup.Lookups;
059:
060: /**
061: * Replaces the type usages in a project with those
062: * of the super type, where applicable
063: * @author Bharath Ravi Kumar
064: */
065: public final class UseSuperTypeRefactoring extends AbstractRefactoring {
066:
067: private final TreePathHandle javaClassHandle;
068: private ElementHandle<TypeElement> super Type;
069:
070: //Forced to create an array since the ComboBoxModel (for the panel)
071: //takes only a vector or an array.
072: private ElementHandle<TypeElement>[] candidateSuperTypes;
073:
074: /**
075: * Creates a new instance of UseSuperTypeRefactoring
076: * @param javaClassHandle The class whose occurences must be replaced by
077: * that of it's supertype
078: */
079: public UseSuperTypeRefactoring(TreePathHandle javaClassHandle) {
080: super (Lookups.fixed(javaClassHandle));
081: this .javaClassHandle = javaClassHandle;
082: deriveSuperTypes(javaClassHandle);
083: }
084:
085: /**
086: * Returns the type whose occurence must be replaced by that of it's supertype.
087: * @return The array of elements to be safely deleted
088: */
089: public TreePathHandle getTypeElement() {
090: return javaClassHandle;
091: }
092:
093: /**
094: * Sets the SuperType to be used by this refactoring
095: * @param superClass The SuperType to be used by this refactoring
096: */
097: public void setTargetSuperType(ElementHandle<TypeElement> super Class) {
098: this .super Type = super Class;
099: }
100:
101: /**
102: * Returns the SuperType used by this refactoring
103: * @return superClass The SuperType used by this refactoring
104: */
105: public ElementHandle<TypeElement> getTargetSuperType() {
106: return this .super Type;
107: }
108:
109: /**
110: * Returns the possible SuperTypes that could be used for the initial Type
111: * @return The list of possible SuperTypes for the current type
112: */
113: public ElementHandle<TypeElement>[] getCandidateSuperTypes() {
114: return candidateSuperTypes;
115: }
116:
117: //private helper methods follow
118:
119: private void deriveSuperTypes(final TreePathHandle javaClassHandle) {
120:
121: JavaSource javaSrc = JavaSource.forFileObject(javaClassHandle
122: .getFileObject());
123: try {
124: javaSrc.runUserActionTask(
125: new CancellableTask<CompilationController>() {
126:
127: public void cancel() {
128: }
129:
130: public void run(
131: CompilationController complController)
132: throws IOException {
133:
134: complController
135: .toPhase(Phase.ELEMENTS_RESOLVED);
136: TypeElement javaClassElement = (TypeElement) javaClassHandle
137: .resolveElement(complController);
138: candidateSuperTypes = deduceSuperTypes(
139: javaClassElement, complController);
140: }
141: }, false);
142: } catch (IOException ioex) {
143: ioex.printStackTrace();
144: }
145: return;
146: }
147:
148: // --private helper methods follow--
149:
150: /* Checks each Object in the collection that's
151: * passed as the second parameter, converts it to a raw type from
152: * a ParameterizedType, if necessary, and adds it to the candidateSuperTypesList
153: */
154: //TODO: Rewrite this for retouche
155: private void reduceParamTypes(Collection candidateSuperTypeList,
156: Collection javaClassList) {
157: // Iterator interfacesIterator = javaClassList.iterator();
158: // while(interfacesIterator.hasNext()){
159: // Object superClass = (Object) interfacesIterator.next();
160: // if(superClass instanceof ParameterizedType)
161: // superClass = ((ParameterizedType)superClass).getDefinition();
162: // candidateSuperTypeList.add(superClass);
163: // }
164: }
165:
166: private ElementHandle[] deduceSuperTypes(
167: TypeElement subTypeElement, CompilationController compCtlr) {
168:
169: TypeMirror subtypeMirror = subTypeElement.asType();
170: Types types = compCtlr.getTypes();
171: Comparator<TypeMirror> comparator = new TypeMirrorComparator();
172: //TODO:The working set (workingTypeMirrors) doesn't have to be a TreeSet.
173: //Why unnecessarily do the additional work of ordering in an intermediate Set?
174: TreeSet<TypeMirror> finalSuperTypeMirrors = new TreeSet<TypeMirror>(
175: comparator);
176: TreeSet<TypeMirror> workingTypeMirrors = new TreeSet<TypeMirror>(
177: comparator);
178: workingTypeMirrors.add(subtypeMirror);
179: getAllSuperIFs(subtypeMirror, workingTypeMirrors,
180: finalSuperTypeMirrors, compCtlr);
181: ElementHandle[] super TypeHandles = new ElementHandle[finalSuperTypeMirrors
182: .size()];
183: int index = 0;
184: for (Iterator<TypeMirror> it = finalSuperTypeMirrors.iterator(); it
185: .hasNext();) {
186: TypeMirror typeMirror = it.next();
187: super TypeHandles[index++] = ElementHandle.create(types
188: .asElement(typeMirror));
189: }
190: return super TypeHandles;
191:
192: }
193:
194: private void getAllSuperIFs(TypeMirror subTypeMirror,
195: Collection<TypeMirror> uniqueIFs,
196: Collection<TypeMirror> finalIFCollection,
197: CompilationController compCtlr) {
198: Types types = compCtlr.getTypes();
199: Iterator<? extends TypeMirror> subTypeIFs = types
200: .directSupertypes(subTypeMirror).iterator();
201: while (subTypeIFs.hasNext()) {
202: TypeMirror super Type = subTypeIFs.next();
203: finalIFCollection.add(super Type);
204: if (!uniqueIFs.contains(super Type)) {
205: getAllSuperIFs(super Type, uniqueIFs, finalIFCollection,
206: compCtlr);
207: }
208: }
209: return;
210: }
211:
212: //Compares two types alphabetically based on their fully qualified name
213: private static class TypeMirrorComparator implements
214: Comparator<TypeMirror> {
215:
216: public int compare(TypeMirror type1, TypeMirror type2) {
217: return type1.toString().compareTo(type2.toString());
218: }
219:
220: }
221:
222: }
|