001: /*
002: * Author: Chris Seguin
003: *
004: * This software has been developed under the copyleft
005: * rules of the GNU General Public License. Please
006: * consult the GNU General Public License for more
007: * details about use and distribution of this software.
008: */
009: package org.acm.seguin.refactor;
010:
011: import java.io.File;
012: import java.io.FileWriter;
013: import java.io.IOException;
014: import java.io.PrintWriter;
015: import java.text.DateFormat;
016: import java.util.Date;
017: import java.util.Enumeration;
018: import java.util.Vector;
019: import net.sourceforge.jrefactory.factory.NameFactory;
020: import org.acm.seguin.refactor.undo.UndoAction;
021: import org.acm.seguin.refactor.undo.UndoStack;
022: import org.acm.seguin.summary.FileSummary;
023: import org.acm.seguin.summary.PackageSummary;
024: import org.acm.seguin.summary.Summary;
025: import org.acm.seguin.summary.TypeDeclSummary;
026: import org.acm.seguin.summary.TypeSummary;
027: import org.acm.seguin.summary.query.GetTypeSummary;
028: import org.acm.seguin.util.FileSettings;
029:
030: /**
031: * Adds a class that is either a parent or a child of an existing class.
032: *
033: *@author Chris Seguin
034: */
035: public abstract class Refactoring {
036: private ComplexTransform complex = null;
037: private static Class transform = DefaultComplexTransform.class;
038:
039: /**
040: * The repackage refactoring
041: */
042: public final static int REPACKAGE = 1;
043: /**
044: * The rename class refactoring
045: */
046: public final static int RENAME_CLASS = 2;
047: /**
048: * The add child refactoring
049: */
050: public final static int ADD_CHILD = 4;
051: /**
052: * The add parent refactoring
053: */
054: public final static int ADD_PARENT = 3;
055: /**
056: * The remove class refactoring
057: */
058: public final static int REMOVE_CLASS = 5;
059: /**
060: * Extracts the interface
061: */
062: public final static int EXTRACT_INTERFACE = 6;
063:
064: /**
065: * Pushes the field into the parent class
066: */
067: public final static int PUSH_DOWN_FIELD = 101;
068: /**
069: * Pushes the field into the child classes
070: */
071: public final static int PUSH_UP_FIELD = 102;
072: /**
073: * Renames the field
074: */
075: public final static int RENAME_FIELD = 103;
076:
077: /**
078: * Pushes the method into the parent class
079: */
080: public final static int PUSH_UP_METHOD = 201;
081: /**
082: * Pushes the method signature into the parent class
083: */
084: public final static int PUSH_UP_ABSTRACT_METHOD = 202;
085: /**
086: * Pushes the method into the child classes
087: */
088: public final static int PUSH_DOWN_METHOD = 203;
089: /**
090: * Moves the method into another class
091: */
092: public final static int MOVE_METHOD = 204;
093: /**
094: * Extracts code from one method to create a new method
095: */
096: public final static int EXTRACT_METHOD = 205;
097: /**
098: * Extracts code from one method to create a new method
099: */
100: public final static int RENAME_METHOD = 206;
101:
102: /**
103: * Renames a parameter
104: */
105: public final static int RENAME_PARAMETER = 251;
106:
107: /**
108: * Constructor for the Refactoring object
109: */
110: public Refactoring() {
111: }
112:
113: /**
114: * Gets the description of the refactoring
115: *
116: *@return the description
117: */
118: public abstract String getDescription();
119:
120: /**
121: * Gets the id for this refactoring to track which refactorings are used.
122: *
123: *@return the id
124: */
125: public abstract int getID();
126:
127: /**
128: * Main program that performst the transformation
129: *
130: *@exception RefactoringException Description of Exception
131: */
132: public void run() throws RefactoringException {
133: try {
134: preconditions();
135: transform();
136: UndoStack.get().done();
137:
138: recordUsage();
139: } catch (RefactoringException re) {
140: throw re;
141: } catch (Throwable thrown) {
142: thrown.printStackTrace(System.out);
143: }
144: }
145:
146: /**
147: * This sets the class that does complex transforms.
148: *
149: * If not called the org.acm.seguin.refactor.ComplexTransform class
150: * is used.
151: *
152: * @param complexTransform a class that implements org.acm.seguin.refactor.ComplexTransform
153: * @throws IllegalArgumentException if the class cannot be instantiated or does not implement ComplexTransform
154: */
155: public static void setComplexTransform(Class complexTransform)
156: throws IllegalArgumentException {
157: try {
158: if (!(transform.newInstance() instanceof ComplexTransform)) {
159: throw new IllegalArgumentException(
160: "the undo class must implement org.acm.seguin.refactor.ComplexTransform");
161: }
162: } catch (IllegalAccessException ex) {
163: IllegalArgumentException e = new IllegalArgumentException(
164: "your ComplexTransform class cannot be accessed");
165: e.initCause(ex);
166: } catch (InstantiationException ex) {
167: IllegalArgumentException e = new IllegalArgumentException(
168: "your ComplexTransform class must have a zero argument constructor");
169: e.initCause(ex);
170: }
171: transform = complexTransform;
172: }
173:
174: /**
175: * Gets a complex transform object for this refactoring
176: *
177: *@return The ComplexTransform value
178: */
179: protected ComplexTransform getComplexTransform() {
180: if (complex == null) {
181: UndoAction undo = UndoStack.get().add(this );
182: try {
183: complex = (ComplexTransform) transform.newInstance();
184: complex.setUndoAction(undo);
185: } catch (IllegalAccessException ex) {
186: // should not happen as checked in setComplexTransform
187: } catch (InstantiationException ex) {
188: // should not happen as checked in setComplexTransform
189: }
190: //complex = new ComplexTransform(undo);
191: }
192:
193: return complex;
194: }
195:
196: /**
197: * Describes the preconditions that must be true for this refactoring to be
198: * applied
199: *
200: *@exception RefactoringException thrown if one or more of the
201: * preconditions is not satisfied. The text of the exception provides a
202: * hint of what went wrong.
203: */
204: protected abstract void preconditions() throws RefactoringException;
205:
206: /**
207: * Performs the transform on the rest of the classes
208: */
209: protected abstract void transform();
210:
211: /**
212: * Check that we are allowed to adjust the destination
213: *
214: *@param loop the summary
215: *@param message the message
216: *@exception RefactoringException problem report
217: */
218: protected void checkDestinationFile(Summary loop, String message)
219: throws RefactoringException {
220: while (loop != null) {
221: if (loop instanceof FileSummary) {
222: FileSummary temp = (FileSummary) loop;
223: if (temp.getFile() == null) {
224: throw new RefactoringException(message);
225: }
226:
227: loop = null;
228: } else {
229: loop = loop.getParent();
230: }
231: }
232: }
233:
234: /**
235: * Record the refactoring usage
236: */
237: private void recordUsage() {
238: try {
239: File dir = new File(
240: FileSettings.getRefactorySettingsRoot(), "log.txt");
241: FileWriter fileWriter = new FileWriter(dir, true);
242: PrintWriter output = new PrintWriter(fileWriter);
243: DateFormat df = DateFormat.getDateTimeInstance(
244: DateFormat.SHORT, DateFormat.SHORT);
245: output.println(getID() + ", " + df.format(new Date()));
246: output.close();
247: } catch (IOException ioe) {
248: }
249: }
250: }
|