001: package org.acm.seguin.refactor.type;
002:
003: import java.io.File;
004: import java.util.Iterator;
005: import java.util.LinkedList;
006: import java.util.StringTokenizer;
007: import net.sourceforge.jrefactory.ast.ASTName;
008: import org.acm.seguin.summary.*;
009: import org.acm.seguin.summary.query.GetTypeSummary;
010: import org.acm.seguin.refactor.AddImportTransform;
011: import org.acm.seguin.refactor.TransformAST;
012: import org.acm.seguin.refactor.RemoveImportTransform;
013: import org.acm.seguin.refactor.ComplexTransform;
014:
015: /**
016: * Renames a class from one name to another.
017: *
018: *@author Chris Seguin
019: */
020: public class RenameClassVisitor extends TypeChangeVisitor {
021: // Instance Variables
022: /**
023: * Description of the Field
024: */
025: protected String packageName;
026: /**
027: * Description of the Field
028: */
029: protected String oldClassName;
030: /**
031: * Description of the Field
032: */
033: protected String newClassName;
034: private File base;
035: private File targetFile;
036:
037: /**
038: * Determine if anything in this tree references these classes.
039: *
040: *@param base the base directory
041: *@param packageName Description of Parameter
042: *@param oldClass Description of Parameter
043: *@param newClass Description of Parameter
044: *@param complex Description of Parameter
045: */
046: public RenameClassVisitor(String packageName, String oldClass,
047: String newClass, File base, ComplexTransform complex) {
048: super (complex);
049: this .packageName = packageName;
050: this .base = base;
051: oldClassName = oldClass;
052: newClassName = newClass;
053: }
054:
055: /**
056: * Gets the File Specific Transform
057: *
058: *@param summary Gets a file specific transform
059: *@return The FileSpecificTransform value
060: */
061: protected TransformAST getFileSpecificTransform(FileSummary summary) {
062: if (isRenamingTarget(summary)) {
063: ASTName oldName = new ASTName();
064: oldName.fromString(oldClassName);
065: ASTName newName = new ASTName();
066: newName.fromString(newClassName);
067:
068: return new RenameTypeTransform(oldName, newName,
069: GetTypeSummary.query(packageName, oldClassName));
070: }
071:
072: return null;
073: }
074:
075: /**
076: * Gets the New Imports transform
077: *
078: *@param node the file summary
079: *@param className the name of the class that is changing
080: *@return The NewImports value
081: */
082: protected AddImportTransform getNewImports(FileSummary node,
083: String className) {
084: if (GetTypeSummary.query(node, newClassName) == null) {
085: return new AddImportTransform(packageName, newClassName);
086: } else {
087: return null;
088: }
089: }
090:
091: /**
092: * Gets the Remove Imports transform
093: *
094: *@param node the import summary
095: *@return The transform
096: */
097: protected RemoveImportTransform getRemoveImportTransform(
098: ImportSummary node) {
099: return new RemoveImportTransform(packageName, oldClassName);
100: }
101:
102: /**
103: * Gets the AppropriateClasses attribute of the TypeChangeVisitor object
104: *
105: *@param node Description of Parameter
106: *@return The AppropriateClasses value
107: */
108: protected LinkedList getAppropriateClasses(FileSummary node) {
109: LinkedList result = new LinkedList();
110: result.add(oldClassName);
111: return result;
112: }
113:
114: /**
115: * Gets the reference to the file where the refactored output should be sent
116: *
117: *@param node the files summary
118: *@return The NewFile value
119: */
120: protected File getNewFile(FileSummary node) {
121: File current = base;
122:
123: StringTokenizer tok = new StringTokenizer(packageName, ".");
124: while (tok.hasMoreTokens()) {
125: current = new File(current, tok.nextToken());
126: }
127:
128: File input = new File(current, oldClassName + ".java");
129: if (checkFiles(input, node.getFile())) {
130: File result = new File(current, newClassName + ".java");
131: return result;
132: } else {
133: return node.getFile();
134: }
135: }
136:
137: /**
138: * Return the current package
139: *
140: *@return the current package of the class
141: */
142: protected String getCurrentPackage() {
143: return packageName;
144: }
145:
146: /**
147: * Gets the new name
148: *
149: *@return an ASTName containing the new name
150: */
151: protected ASTName getNewName() {
152: ASTName result = new ASTName();
153: result.fromString(packageName);
154: result.addNamePart(newClassName);
155: return result;
156: }
157:
158: /**
159: * Gets the RenamingTransform
160: *
161: *@param refactoring the refactoring
162: *@param node the file summary to reference
163: *@param className the name of the class that is changing
164: */
165: protected void addRenamingTransforms(ComplexTransform refactoring,
166: FileSummary node, String className) {
167: ASTName oldOne = new ASTName();
168: oldOne.addNamePart(oldClassName);
169:
170: TypeSummary importedType = GetTypeSummary.query(node,
171: newClassName);
172: if ((importedType != null) && isRenamingTarget(node)) {
173: renameRefactoringTarget(refactoring, node, className,
174: oldOne, importedType);
175: } else if (importedType != null) {
176: alreadyImportsType(refactoring, oldOne, node, importedType);
177: } else {
178: simpleRename(refactoring, oldOne);
179: }
180:
181: refactoring.add(new RenameTypeTransform(getOldName(),
182: getNewName(), GetTypeSummary.query(packageName,
183: oldClassName)));
184: }
185:
186: /**
187: * We are performing the transformation on a refactoring that already has
188: * that type imported from another class
189: *
190: *@param refactoring the complex transformation
191: *@param oldOne the old class name
192: *@param node the file that is being changed
193: *@param importedType the type that we are supposedly importing
194: */
195: protected void alreadyImportsType(ComplexTransform refactoring,
196: ASTName oldOne, FileSummary node, TypeSummary importedType) {
197: refactoring.add(new RenameTypeTransform(oldOne, getNewName(),
198: GetTypeSummary.query(packageName, oldClassName)));
199: }
200:
201: /**
202: * Checks to see if this is the target
203: *
204: *@param summary the file summary
205: *@return true if this file summary represents the file that is
206: * being renamed
207: */
208: private boolean isRenamingTarget(FileSummary summary) {
209: if (targetFile == null) {
210: File current = base;
211:
212: StringTokenizer tok = new StringTokenizer(packageName, ".");
213: while (tok.hasMoreTokens()) {
214: current = new File(current, tok.nextToken());
215: }
216:
217: targetFile = new File(current, oldClassName + ".java");
218: }
219:
220: return checkFiles(targetFile, summary.getFile());
221: }
222:
223: /**
224: * Creates a name from a type summary
225: *
226: *@param summary the type summary
227: *@return the name
228: */
229: private ASTName getImport(TypeSummary summary) {
230: ASTName name = new ASTName();
231:
232: Summary current = summary.getParent();
233: while (!(current instanceof PackageSummary)) {
234: current = current.getParent();
235: }
236:
237: name.fromString(((PackageSummary) current).getName());
238: name.addNamePart(summary.getName());
239:
240: return name;
241: }
242:
243: /**
244: * Gets the old name
245: *
246: *@return an ASTName containing the old name
247: */
248: private ASTName getOldName() {
249: ASTName result = new ASTName();
250: result.fromString(packageName);
251: result.addNamePart(oldClassName);
252: return result;
253: }
254:
255: /**
256: * This file does not import the type, so the rename operation is simple
257: *
258: *@param refactoring the complex transformation
259: *@param oldOne the old one
260: */
261: private void simpleRename(ComplexTransform refactoring,
262: ASTName oldOne) {
263: ASTName newOne = new ASTName();
264: newOne.addNamePart(newClassName);
265:
266: refactoring.add(new RenameTypeTransform(oldOne, newOne,
267: GetTypeSummary.query(packageName, oldClassName)));
268: }
269:
270: /**
271: * We are attempting to perform the rename operation on the targeted file.
272: * This change is complex because the file already imported another class
273: * with the same name
274: *
275: *@param refactoring the complex transformation
276: *@param node the node
277: *@param className the new name
278: *@param oldOne the old class
279: *@param importedType the type that was imported that has the same name
280: */
281: private void renameRefactoringTarget(ComplexTransform refactoring,
282: FileSummary node, String className, ASTName oldOne,
283: TypeSummary importedType) {
284: ASTName newOne = new ASTName();
285: newOne.addNamePart(newClassName);
286:
287: ASTName importedTypeName = getImport(importedType);
288:
289: refactoring.add(new RenameTypeTransform(newOne,
290: importedTypeName, GetTypeSummary.query(packageName,
291: oldClassName)));
292: refactoring.add(new RemoveImportTransform(importedTypeName));
293: refactoring.add(new RenameTypeTransform(oldOne, newOne,
294: GetTypeSummary.query(packageName, oldClassName)));
295: }
296:
297: /**
298: * Description of the Method
299: *
300: *@param file1 Description of Parameter
301: *@param file2 Description of Parameter
302: *@return Description of the Returned Value
303: */
304: private boolean checkFiles(File file1, File file2) {
305: try {
306: String one = file1.getCanonicalPath();
307: String two = file2.getCanonicalPath();
308: return one.equals(two);
309: } catch (java.io.IOException ioe) {
310: return false;
311: }
312: }
313: }
|