001: package com.ibm.sigtest;
002:
003: import java.io.BufferedReader;
004: import java.io.File;
005: import java.io.FileOutputStream;
006: import java.io.FileReader;
007: import java.io.IOException;
008: import java.io.OutputStream;
009: import java.io.PrintWriter;
010: import java.lang.reflect.Constructor;
011: import java.lang.reflect.Method;
012: import java.lang.reflect.Modifier;
013: import java.util.Arrays;
014: import java.util.Collection;
015: import java.util.Iterator;
016: import java.util.List;
017: import java.util.StringTokenizer;
018: import java.util.Vector;
019:
020: /**
021: * This class implements static utility methods for use by the signature test
022: * tool.
023: * @author Matthew J. Duftler (duftler@us.ibm.com)
024: */
025: public class SigTestUtils {
026:
027: /**
028: * This method builds a new project description by using an existing one as
029: * a reference. The new project description is built by resolving each class
030: * specified in the reference description, and adding their signatures to
031: * the newly built project.
032: * @param referencePD the reference project description
033: * @return the new project description
034: */
035: public static ProjectDesc getProjectDesc(ProjectDesc referencePD) {
036: ProjectDesc candidatePD = new ProjectDesc("CandidateImpl");
037: Iterator iterator = referencePD.getClassDescs().iterator();
038:
039: while (iterator.hasNext()) {
040: ClassDesc referenceCD = (ClassDesc) iterator.next();
041: String className = referenceCD.getName();
042: ClassDesc candidateCD = null;
043:
044: try {
045: Class candidateClass = Class.forName(className);
046:
047: candidateCD = getClassDesc(candidateClass);
048: } catch (ClassNotFoundException e) {
049: }
050:
051: if (candidateCD != null) {
052: candidatePD.addClassDesc(candidateCD);
053: }
054: }
055:
056: return candidatePD;
057: }
058:
059: public static ClassDesc getClassDesc(Class theClass) {
060: String className = theClass.getName();
061: ClassDesc classDesc = new ClassDesc(className, theClass
062: .getModifiers());
063: Class super Class = theClass.getSuperclass();
064:
065: if (super Class != null) {
066: classDesc.setSuperClassName(getClassName(super Class));
067: }
068:
069: List interfaceNames = getTypeNames(theClass.getInterfaces());
070:
071: classDesc.setInterfaceNames(interfaceNames);
072:
073: List constructorDescs = getConstructorDescs(className, theClass
074: .getDeclaredConstructors());
075:
076: classDesc.setConstructorDescs(constructorDescs);
077:
078: List methodDescs = getMethodDescs(theClass.getDeclaredMethods());
079:
080: classDesc.setMethodDescs(methodDescs);
081:
082: return classDesc;
083: }
084:
085: public static List getConstructorDescs(String className,
086: Constructor[] constructors) {
087: List constructorDescs = new Vector();
088:
089: for (int i = 0; i < constructors.length; i++) {
090: MethodDesc constructorDesc = new MethodDesc(className,
091: constructors[i].getModifiers(), null,
092: getTypeNames(constructors[i].getParameterTypes()),
093: getTypeNames(constructors[i].getExceptionTypes()));
094:
095: constructorDescs.add(constructorDesc);
096: }
097:
098: return constructorDescs;
099: }
100:
101: public static List getMethodDescs(Method[] methods) {
102: List methodDescs = new Vector();
103:
104: for (int i = 0; i < methods.length; i++) {
105: MethodDesc methodDesc = new MethodDesc(
106: methods[i].getName(), methods[i].getModifiers(),
107: getClassName(methods[i].getReturnType()),
108: getTypeNames(methods[i].getParameterTypes()),
109: getTypeNames(methods[i].getExceptionTypes()));
110:
111: methodDescs.add(methodDesc);
112: }
113:
114: return methodDescs;
115: }
116:
117: public static List getTypeNames(Class[] types) {
118: List typeNames = new Vector();
119:
120: for (int i = 0; i < types.length; i++) {
121: typeNames.add(getClassName(types[i]));
122: }
123:
124: return typeNames;
125: }
126:
127: public static String listToString(List list) {
128: StringBuffer strBuf = new StringBuffer();
129: int size = list.size();
130:
131: for (int i = 0; i < size; i++) {
132: strBuf.append((i > 0 ? "," : "") + list.get(i));
133: }
134:
135: return strBuf.toString();
136: }
137:
138: public static List stringToList(String str, String delim) {
139: return Arrays.asList(tokenize(str, delim));
140: }
141:
142: public static String[] tokenize(String tokenStr, String delim) {
143: StringTokenizer strTok = new StringTokenizer(tokenStr, delim);
144: String[] tokens = new String[strTok.countTokens()];
145:
146: for (int i = 0; i < tokens.length; i++) {
147: tokens[i] = strTok.nextToken();
148: }
149:
150: return tokens;
151: }
152:
153: public static boolean objectsEqual(Object obj1, Object obj2) {
154: if (obj1 == null) {
155: return (obj2 == null);
156: } else {
157: return obj1.equals(obj2);
158: }
159: }
160:
161: public static boolean collectionsMatch(Collection c1, Collection c2) {
162: if (c1 == null) {
163: return (c2 == null);
164: } else {
165: return c1.containsAll(c2) && c2.containsAll(c1);
166: }
167: }
168:
169: public static String getExpandedMethodList(List list) {
170: StringBuffer strBuf = new StringBuffer("[");
171: int size = list.size();
172:
173: for (int i = 0; i < size; i++) {
174: strBuf.append((i > 0 ? ", " : "")
175: + ((MethodDesc) list.get(i)).toString(true));
176: }
177:
178: strBuf.append("]");
179:
180: return strBuf.toString();
181: }
182:
183: public static String getCondensedClassList(List list) {
184: StringBuffer strBuf = new StringBuffer("[");
185: int size = list.size();
186:
187: for (int i = 0; i < size; i++) {
188: strBuf.append((i > 0 ? ", " : "")
189: + ((ClassDesc) list.get(i)).getName());
190: }
191:
192: strBuf.append("]");
193:
194: return strBuf.toString();
195: }
196:
197: public static void findExtras(Collection reference,
198: Collection candidate, List referenceExtras,
199: List candidateExtras) {
200: referenceExtras.addAll(reference);
201: referenceExtras.removeAll(candidate);
202: candidateExtras.addAll(candidate);
203: candidateExtras.removeAll(reference);
204:
205: if (candidateExtras.size() > 0) {
206: Iterator memberDescs = candidateExtras.iterator();
207:
208: while (memberDescs.hasNext()) {
209: MemberDesc memberDesc = (MemberDesc) memberDescs.next();
210: int modifiers = memberDesc.getModifiers();
211:
212: if (Modifier.isPrivate(modifiers)
213: || !(Modifier.isProtected(modifiers) || Modifier
214: .isPublic(modifiers))) {
215: memberDescs.remove();
216: }
217: }
218: }
219: }
220:
221: public static void findExtraClasses(ProjectDesc referencePD,
222: ProjectDesc candidatePD, List referenceExtras,
223: List candidateExtras) {
224: referenceExtras.addAll(referencePD.getClassDescs());
225: candidateExtras.addAll(candidatePD.getClassDescs());
226:
227: Iterator iterator = referenceExtras.iterator();
228:
229: while (iterator.hasNext()) {
230: ClassDesc referenceCD = (ClassDesc) iterator.next();
231: ClassDesc candidateCD = candidatePD
232: .getClassDesc(referenceCD.getName());
233:
234: if (candidateCD != null) {
235: iterator.remove();
236: }
237: }
238:
239: iterator = candidateExtras.iterator();
240:
241: while (iterator.hasNext()) {
242: ClassDesc candidateCD = (ClassDesc) iterator.next();
243: ClassDesc referenceCD = referencePD
244: .getClassDesc(candidateCD.getName());
245:
246: if (referenceCD != null) {
247: iterator.remove();
248: }
249: }
250: }
251:
252: /*
253: * This method will return the correct name for a class object representing
254: * a primitive, a single instance of a class, as well as n-dimensional
255: * arrays of primitives or instances. This logic is needed to handle the
256: * string returned from Class.getName(). If the class object represents a
257: * single instance (or a primitive), Class.getName() returns the
258: * fully-qualified name of the class and no further work is needed. However,
259: * if the class object represents an array (of n dimensions),
260: * Class.getName() returns a Descriptor (the Descriptor grammar is defined
261: * in section 4.3 of the Java VM Spec). This method will parse the
262: * Descriptor if necessary.
263: */
264: public static String getClassName(Class targetClass) {
265: String className = targetClass.getName();
266:
267: return targetClass.isArray() ? parseDescriptor(className)
268: : className;
269: }
270:
271: /*
272: * See the comment above for getClassName(targetClass)...
273: */
274: private static String parseDescriptor(String className) {
275: char[] classNameChars = className.toCharArray();
276: int arrayDim = 0;
277: int i = 0;
278:
279: while (classNameChars[i] == '[') {
280: arrayDim++;
281: i++;
282: }
283:
284: StringBuffer classNameBuf = new StringBuffer();
285:
286: switch (classNameChars[i++]) {
287: case 'B':
288: classNameBuf.append("byte");
289: break;
290: case 'C':
291: classNameBuf.append("char");
292: break;
293: case 'D':
294: classNameBuf.append("double");
295: break;
296: case 'F':
297: classNameBuf.append("float");
298: break;
299: case 'I':
300: classNameBuf.append("int");
301: break;
302: case 'J':
303: classNameBuf.append("long");
304: break;
305: case 'S':
306: classNameBuf.append("short");
307: break;
308: case 'Z':
309: classNameBuf.append("boolean");
310: break;
311: case 'L':
312: classNameBuf.append(classNameChars, i,
313: classNameChars.length - i - 1);
314: break;
315: }
316:
317: for (i = 0; i < arrayDim; i++)
318: classNameBuf.append("[]");
319:
320: return classNameBuf.toString();
321: }
322:
323: private static OutputStream getOutputStream(String root,
324: String name, boolean overwrite, boolean verbose)
325: throws IOException {
326: if (root != null) {
327: File directory = new File(root);
328:
329: if (!directory.exists()) {
330: if (!directory.mkdirs()) {
331: throw new IOException(
332: "Failed to create directory '" + root
333: + "'.");
334: } else if (verbose) {
335: System.out.println("Created directory '"
336: + directory.getAbsolutePath() + "'.");
337: }
338: }
339: }
340:
341: File file = new File(root, name);
342: String absolutePath = file.getAbsolutePath();
343:
344: if (file.exists()) {
345: if (!overwrite) {
346: throw new IOException("File '" + absolutePath
347: + "' already exists. "
348: + "Please remove it or enable the "
349: + "overwrite option.");
350: } else {
351: file.delete();
352:
353: if (verbose) {
354: System.out.println("Deleted file '" + absolutePath
355: + "'.");
356: }
357: }
358: }
359:
360: FileOutputStream fos = new FileOutputStream(absolutePath);
361:
362: if (verbose) {
363: System.out.println("Created file '" + absolutePath + "'.");
364: }
365:
366: return fos;
367: }
368:
369: public static void generateProjectFile(String classListFile,
370: String projectFile, boolean overwrite) throws IOException,
371: ClassNotFoundException {
372: FileReader in = new FileReader(classListFile);
373: BufferedReader buf = new BufferedReader(in);
374: OutputStream out = getOutputStream(null, projectFile,
375: overwrite, true);
376: PrintWriter pw = new PrintWriter(out);
377: String tempLine;
378:
379: while ((tempLine = buf.readLine()) != null) {
380: pw.println(getClassDesc(Class.forName(tempLine)));
381: }
382:
383: pw.flush();
384: pw.close();
385: buf.close();
386: in.close();
387: }
388: }
|