001: package org.acm.seguin.refactor.type;
002:
003: import java.io.File;
004: import java.io.IOException;
005: import java.util.Vector;
006: import java.util.Enumeration;
007: import net.sourceforge.jrefactory.factory.NameFactory;
008: import org.acm.seguin.summary.Summary;
009: import org.acm.seguin.summary.TypeSummary;
010: import org.acm.seguin.summary.TypeDeclSummary;
011: import org.acm.seguin.summary.FileSummary;
012: import org.acm.seguin.summary.PackageSummary;
013: import org.acm.seguin.summary.query.GetTypeSummary;
014: import org.acm.seguin.refactor.Refactoring;
015: import org.acm.seguin.refactor.RefactoringException;
016: import org.acm.seguin.refactor.EliminatePackageImportVisitor;
017:
018: /**
019: * Adds a class that is either a parent or a child of an existing class.
020: *
021: *@author Chris Seguin
022: */
023: public abstract class AddClassRefactoring extends Refactoring {
024: private Vector summaryList;
025: private String className = null;
026:
027: /**
028: * Constructor for the AddClassRefactoring object
029: */
030: public AddClassRefactoring() {
031: summaryList = new Vector();
032: }
033:
034: /**
035: * Sets the name of the new class
036: *
037: *@param value the name of the new class
038: */
039: protected void setNewClassName(String value) {
040: className = value;
041: }
042:
043: /**
044: * Gets the name of the new class
045: *
046: *@return the name
047: */
048: protected String getNewClassName() {
049: return className;
050: }
051:
052: /**
053: * Adds a target class - either the parent or the child, depending on what
054: * we are adding
055: *
056: *@param summary the summary to be extended
057: */
058: protected void addTargetClass(TypeSummary summary) {
059: if (summary != null) {
060: summaryList.addElement(summary);
061: }
062: }
063:
064: /**
065: * Describes the preconditions that must be true for this refactoring to be
066: * applied
067: *
068: *@exception RefactoringException thrown if one or more of the
069: * preconditions is not satisfied. The text of the exception provides a
070: * hint of what went wrong.
071: */
072: protected void preconditions() throws RefactoringException {
073: if (summaryList.size() == 0) {
074: throw new RefactoringException(
075: "Unable to find type to extend");
076: }
077:
078: if (className == null) {
079: throw new RefactoringException(
080: "New class name is not specified");
081: }
082:
083: // Get the package
084: PackageSummary summary = getPackageSummary((Summary) summaryList
085: .elementAt(0));
086: TypeSummary abstractParent = GetTypeSummary.query(summary,
087: className);
088: if (abstractParent != null) {
089: throw new RefactoringException(
090: "Type with that name already exists");
091: }
092:
093: TypeSummary anySummary = (TypeSummary) summaryList.elementAt(0);
094: TypeSummary originalParent = GetTypeSummary.query(anySummary
095: .getParentClass());
096: Enumeration enumx = summaryList.elements();
097: while (enumx.hasMoreElements()) {
098: TypeSummary typeSummary = (TypeSummary) enumx.nextElement();
099: if (typeSummary.isInterface()) {
100: throw new RefactoringException(
101: "This refactoring only works for classes, not interfaces");
102: }
103:
104: FileSummary fileSummary = (FileSummary) typeSummary
105: .getParent();
106: TypeSummary referenced = GetTypeSummary.query(fileSummary,
107: className);
108: if (referenced != null) {
109: throw new RefactoringException(
110: "New class already exists relative to "
111: + typeSummary.getName());
112: }
113:
114: if (!isSameParent(originalParent, GetTypeSummary
115: .query(typeSummary.getParentClass()))) {
116: throw new RefactoringException(
117: "Existing types don't share the same original parent");
118: }
119: }
120: }
121:
122: /**
123: * Performs the transform on the rest of the classes
124: */
125: protected void transform() {
126: Enumeration enumx = summaryList.elements();
127: while (enumx.hasMoreElements()) {
128: TypeSummary typeSummary = (TypeSummary) enumx.nextElement();
129: transformOriginal(typeSummary);
130: }
131:
132: createClass((TypeSummary) summaryList.elementAt(0), className);
133:
134: EliminatePackageImportVisitor epiv = new EliminatePackageImportVisitor(
135: getComplexTransform());
136: epiv.setPackageSummary(getPackageSummary((Summary) summaryList
137: .elementAt(0)));
138: epiv.visit(null);
139: }
140:
141: /**
142: * Creates a class
143: *
144: *@param existingType the existing type
145: *@param className the name of the new class
146: */
147: protected abstract void createClass(TypeSummary existingType,
148: String className);
149:
150: /**
151: * Transforms the original AST
152: *
153: *@param typeSummary the particular type that is being changed
154: */
155: protected abstract void transformOriginal(TypeSummary typeSummary);
156:
157: /**
158: * Gets the package summary
159: *
160: *@param base Description of Parameter
161: *@return the package summary
162: */
163: private PackageSummary getPackageSummary(Summary base) {
164: Summary current = base;
165: while (!(current instanceof PackageSummary)) {
166: current = current.getParent();
167: }
168: return (PackageSummary) current;
169: }
170:
171: /**
172: * Gets the SameParent attribute of the AddClassRefactoring object
173: *
174: *@param one Description of Parameter
175: *@param two Description of Parameter
176: *@return The SameParent value
177: */
178: private boolean isSameParent(TypeSummary one, TypeSummary two) {
179: if (isObject(one)) {
180: return isObject(two);
181: }
182:
183: if (isObject(two)) {
184: return false;
185: }
186:
187: return one.equals(two);
188: }
189:
190: /**
191: * Gets the Object attribute of the AddClassRefactoring object
192: *
193: *@param item Description of Parameter
194: *@return The Object value
195: */
196: private boolean isObject(TypeSummary item) {
197: if (item == null) {
198: return true;
199: }
200:
201: if (item.getName().equals("Object")) {
202: return true;
203: }
204:
205: return false;
206: }
207: }
|