001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.diff;
034:
035: import java.util.*;
036:
037: import com.jeantessier.classreader.*;
038:
039: public class ClassReport extends Printer implements Comparable {
040: private ClassDifferences differences;
041:
042: private Collection<FeatureDifferences> removedFields = new TreeSet<FeatureDifferences>();
043: private Collection<FeatureDifferences> removedConstructors = new TreeSet<FeatureDifferences>();
044: private Collection<FeatureDifferences> removedMethods = new TreeSet<FeatureDifferences>();
045:
046: private Collection<FeatureDifferences> deprecatedFields = new TreeSet<FeatureDifferences>();
047: private Collection<FeatureDifferences> deprecatedConstructors = new TreeSet<FeatureDifferences>();
048: private Collection<FeatureDifferences> deprecatedMethods = new TreeSet<FeatureDifferences>();
049:
050: private Collection<FieldDifferences> modifiedFields = new TreeSet<FieldDifferences>();
051: private Collection<CodeDifferences> modifiedConstructors = new TreeSet<CodeDifferences>();
052: private Collection<CodeDifferences> modifiedMethods = new TreeSet<CodeDifferences>();
053:
054: private Collection<FeatureDifferences> undeprecatedFields = new TreeSet<FeatureDifferences>();
055: private Collection<FeatureDifferences> undeprecatedConstructors = new TreeSet<FeatureDifferences>();
056: private Collection<FeatureDifferences> undeprecatedMethods = new TreeSet<FeatureDifferences>();
057:
058: private Collection<FeatureDifferences> newFields = new TreeSet<FeatureDifferences>();
059: private Collection<FeatureDifferences> newConstructors = new TreeSet<FeatureDifferences>();
060: private Collection<FeatureDifferences> newMethods = new TreeSet<FeatureDifferences>();
061:
062: public void visitClassDifferences(ClassDifferences differences) {
063: this .differences = differences;
064:
065: for (Differences featureDifference : differences
066: .getFeatureDifferences()) {
067: featureDifference.accept(this );
068: }
069: }
070:
071: public void visitInterfaceDifferences(
072: InterfaceDifferences differences) {
073: this .differences = differences;
074:
075: for (Differences featureDifference : differences
076: .getFeatureDifferences()) {
077: featureDifference.accept(this );
078: }
079: }
080:
081: public void visitFieldDifferences(FieldDifferences differences) {
082: if (differences.isRemoved()) {
083: removedFields.add(differences);
084: }
085:
086: if (differences.isModified()) {
087: modifiedFields.add(differences);
088: }
089:
090: if (differences.isNew()) {
091: newFields.add(differences);
092: }
093:
094: if (isDeprecated()) {
095: deprecatedFields.add(differences);
096: }
097:
098: if (isUndeprecated()) {
099: undeprecatedFields.add(differences);
100: }
101: }
102:
103: public void visitConstructorDifferences(
104: ConstructorDifferences differences) {
105: if (differences.isRemoved()) {
106: removedConstructors.add(differences);
107: }
108:
109: if (differences.isModified()) {
110: modifiedConstructors.add(differences);
111: }
112:
113: if (differences.isNew()) {
114: newConstructors.add(differences);
115: }
116:
117: if (isDeprecated()) {
118: deprecatedConstructors.add(differences);
119: }
120:
121: if (isUndeprecated()) {
122: undeprecatedConstructors.add(differences);
123: }
124: }
125:
126: public void visitMethodDifferences(MethodDifferences differences) {
127: if (differences.isRemoved()) {
128: removedMethods.add(differences);
129: }
130:
131: if (differences.isModified()) {
132: modifiedMethods.add(differences);
133: }
134:
135: if (differences.isNew()) {
136: newMethods.add(differences);
137: }
138:
139: if (isDeprecated()) {
140: deprecatedMethods.add(differences);
141: }
142:
143: if (isUndeprecated()) {
144: undeprecatedMethods.add(differences);
145: }
146: }
147:
148: public String toString() {
149: raiseIndent();
150: raiseIndent();
151:
152: indent().append("<class>").eol();
153: raiseIndent();
154:
155: indent().append("<name>").append(differences.getName()).append(
156: "</name>").eol();
157:
158: if (differences.isDeclarationModified()) {
159: indent().append("<modified-declaration>").eol();
160: raiseIndent();
161:
162: indent().append("<old-declaration").append(
163: breakdownDeclaration(differences.getOldClass()))
164: .append(">")
165: .append(differences.getOldDeclaration()).append(
166: "</old-declaration>").eol();
167: indent().append("<new-declaration").append(
168: breakdownDeclaration(differences.getNewClass()))
169: .append(">")
170: .append(differences.getNewDeclaration()).append(
171: "</new-declaration>").eol();
172:
173: lowerIndent();
174: indent().append("</modified-declaration>").eol();
175: }
176:
177: if (removedFields.size() != 0) {
178: indent().append("<removed-fields>").eol();
179: raiseIndent();
180:
181: for (FeatureDifferences fd : removedFields) {
182: indent().append("<declaration").append(
183: breakdownDeclaration((Field_info) fd
184: .getOldFeature())).append(
185: fd.isInherited() ? " inherited=\"yes\"" : "")
186: .append(">").append(fd.getOldDeclaration())
187: .append("</declaration>").eol();
188: }
189:
190: lowerIndent();
191: indent().append("</removed-fields>").eol();
192: }
193:
194: if (removedConstructors.size() != 0) {
195: indent().append("<removed-constructors>").eol();
196: raiseIndent();
197:
198: for (FeatureDifferences fd : removedConstructors) {
199: indent().append("<declaration").append(
200: breakdownDeclaration((Method_info) fd
201: .getOldFeature())).append(
202: fd.isInherited() ? " inherited=\"yes\"" : "")
203: .append(">").append(fd.getOldDeclaration())
204: .append("</declaration>").eol();
205: }
206:
207: lowerIndent();
208: indent().append("</removed-constructors>").eol();
209: }
210:
211: if (removedMethods.size() != 0) {
212: indent().append("<removed-methods>").eol();
213: raiseIndent();
214:
215: for (FeatureDifferences fd : removedMethods) {
216: indent().append("<declaration").append(
217: breakdownDeclaration((Method_info) fd
218: .getOldFeature())).append(
219: fd.isInherited() ? " inherited=\"yes\"" : "")
220: .append(">").append(fd.getOldDeclaration())
221: .append("</declaration>").eol();
222: }
223:
224: lowerIndent();
225: indent().append("</removed-methods>").eol();
226: }
227:
228: if (deprecatedFields.size() != 0) {
229: indent().append("<deprecated-fields>").eol();
230: raiseIndent();
231:
232: for (FeatureDifferences fd : deprecatedFields) {
233: indent().append("<declaration").append(
234: breakdownDeclaration((Field_info) fd
235: .getNewFeature())).append(">").append(
236: fd.getOldDeclaration())
237: .append("</declaration>").eol();
238: }
239:
240: lowerIndent();
241: indent().append("</deprecated-fields>").eol();
242: }
243:
244: if (deprecatedConstructors.size() != 0) {
245: indent().append("<deprecated-constructors>").eol();
246: raiseIndent();
247:
248: for (FeatureDifferences fd : deprecatedConstructors) {
249: indent().append("<declaration").append(
250: breakdownDeclaration((Method_info) fd
251: .getNewFeature())).append(">").append(
252: fd.getOldDeclaration())
253: .append("</declaration>").eol();
254: }
255:
256: lowerIndent();
257: indent().append("</deprecated-constructors>").eol();
258: }
259:
260: if (deprecatedMethods.size() != 0) {
261: indent().append("<deprecated-methods>").eol();
262: raiseIndent();
263:
264: for (FeatureDifferences fd : deprecatedMethods) {
265: indent().append("<declaration").append(
266: breakdownDeclaration((Method_info) fd
267: .getNewFeature())).append(">").append(
268: fd.getOldDeclaration())
269: .append("</declaration>").eol();
270: }
271:
272: lowerIndent();
273: indent().append("</deprecated-methods>").eol();
274: }
275:
276: if (modifiedFields.size() != 0) {
277: indent().append("<modified-fields>").eol();
278: raiseIndent();
279:
280: for (FieldDifferences fd : modifiedFields) {
281: indent().append("<feature>").eol();
282: raiseIndent();
283:
284: indent().append("<name>").append(fd.getName()).append(
285: "</name>").eol();
286:
287: indent().append("<modified-declaration>").eol();
288: raiseIndent();
289:
290: Field_info oldField = (Field_info) fd.getOldFeature();
291: Field_info newField = (Field_info) fd.getNewFeature();
292: if (fd.isConstantValueDifference()) {
293: indent().append("<old-declaration").append(
294: breakdownDeclaration(oldField)).append(">")
295: .append(oldField.getFullDeclaration())
296: .append("</old-declaration>").eol();
297: indent().append("<new-declaration").append(
298: breakdownDeclaration(newField)).append(">")
299: .append(newField.getFullDeclaration())
300: .append("</new-declaration>").eol();
301: } else {
302: indent().append("<old-declaration").append(
303: breakdownDeclaration(oldField)).append(">")
304: .append(oldField.getDeclaration()).append(
305: "</old-declaration>").eol();
306: indent().append("<new-declaration").append(
307: breakdownDeclaration(newField)).append(">")
308: .append(newField.getDeclaration()).append(
309: "</new-declaration>").eol();
310: }
311:
312: lowerIndent();
313: indent().append("</modified-declaration>").eol();
314:
315: lowerIndent();
316: indent().append("</feature>").eol();
317: }
318:
319: lowerIndent();
320: indent().append("</modified-fields>").eol();
321: }
322:
323: if (modifiedConstructors.size() != 0) {
324: indent().append("<modified-constructors>").eol();
325: raiseIndent();
326:
327: for (CodeDifferences cd : modifiedConstructors) {
328: indent().append("<feature>").eol();
329: raiseIndent();
330:
331: indent().append("<name>").append(cd.getName()).append(
332: "</name>").eol();
333:
334: if (!cd.getOldDeclaration().equals(
335: cd.getNewDeclaration())) {
336: indent().append("<modified-declaration>").eol();
337: raiseIndent();
338: indent().append("<old-declaration").append(
339: breakdownDeclaration((Method_info) cd
340: .getOldFeature())).append(">")
341: .append(cd.getOldDeclaration()).append(
342: "</old-declaration>").eol();
343: indent().append("<new-declaration").append(
344: breakdownDeclaration((Method_info) cd
345: .getNewFeature())).append(">")
346: .append(cd.getNewDeclaration()).append(
347: "</new-declaration>").eol();
348: lowerIndent();
349: indent().append("</modified-declaration>").eol();
350: }
351:
352: if (cd.isCodeDifference()) {
353: indent().append("<modified-code").append(
354: breakdownDeclaration((Method_info) cd
355: .getNewFeature())).append(">")
356: .append(cd.getNewDeclaration()).append(
357: "</modified-code>").eol();
358: }
359:
360: lowerIndent();
361: indent().append("</feature>").eol();
362: }
363:
364: lowerIndent();
365: indent().append("</modified-constructors>").eol();
366: }
367:
368: if (modifiedMethods.size() != 0) {
369: indent().append("<modified-methods>").eol();
370: raiseIndent();
371:
372: for (CodeDifferences md : modifiedMethods) {
373: indent().append("<feature>").eol();
374: raiseIndent();
375:
376: indent().append("<name>").append(md.getName()).append(
377: "</name>").eol();
378:
379: if (!md.getOldDeclaration().equals(
380: md.getNewDeclaration())) {
381: indent().append("<modified-declaration>").eol();
382: raiseIndent();
383: indent().append("<old-declaration").append(
384: breakdownDeclaration((Method_info) md
385: .getOldFeature())).append(">")
386: .append(md.getOldDeclaration()).append(
387: "</old-declaration>").eol();
388: indent().append("<new-declaration").append(
389: breakdownDeclaration((Method_info) md
390: .getNewFeature())).append(">")
391: .append(md.getNewDeclaration()).append(
392: "</new-declaration>").eol();
393: lowerIndent();
394: indent().append("</modified-declaration>").eol();
395: }
396:
397: if (md.isCodeDifference()) {
398: indent().append("<modified-code").append(
399: breakdownDeclaration((Method_info) md
400: .getNewFeature())).append(">")
401: .append(md.getNewDeclaration()).append(
402: "</modified-code>").eol();
403: }
404:
405: lowerIndent();
406: indent().append("</feature>").eol();
407: }
408:
409: lowerIndent();
410: indent().append("</modified-methods>").eol();
411: }
412:
413: if (undeprecatedFields.size() != 0) {
414: indent().append("<undeprecated-fields>").eol();
415: raiseIndent();
416:
417: for (FeatureDifferences fd : undeprecatedFields) {
418: indent().append("<declaration").append(
419: breakdownDeclaration((Field_info) fd
420: .getNewFeature())).append(">").append(
421: fd.getOldDeclaration())
422: .append("</declaration>").eol();
423: }
424:
425: lowerIndent();
426: indent().append("</undeprecated-fields>").eol();
427: }
428:
429: if (undeprecatedConstructors.size() != 0) {
430: indent().append("<undeprecated-constructors>").eol();
431: raiseIndent();
432:
433: for (FeatureDifferences fd : undeprecatedConstructors) {
434: indent().append("<declaration").append(
435: breakdownDeclaration((Method_info) fd
436: .getNewFeature())).append(">").append(
437: fd.getOldDeclaration())
438: .append("</declaration>").eol();
439: }
440:
441: lowerIndent();
442: indent().append("</undeprecated-constructors>").eol();
443: }
444:
445: if (undeprecatedMethods.size() != 0) {
446: indent().append("<undeprecated-methods>").eol();
447: raiseIndent();
448:
449: for (FeatureDifferences fd : undeprecatedMethods) {
450: indent().append("<declaration").append(
451: breakdownDeclaration((Method_info) fd
452: .getNewFeature())).append(">").append(
453: fd.getOldDeclaration())
454: .append("</declaration>").eol();
455: }
456:
457: lowerIndent();
458: indent().append("</undeprecated-methods>").eol();
459: }
460:
461: if (newFields.size() != 0) {
462: indent().append("<new-fields>").eol();
463: raiseIndent();
464:
465: for (FeatureDifferences fd : newFields) {
466: indent().append("<declaration").append(
467: breakdownDeclaration((Field_info) fd
468: .getNewFeature())).append(">").append(
469: fd.getNewDeclaration())
470: .append("</declaration>").eol();
471: }
472:
473: lowerIndent();
474: indent().append("</new-fields>").eol();
475: }
476:
477: if (newConstructors.size() != 0) {
478: indent().append("<new-constructors>").eol();
479: raiseIndent();
480:
481: for (FeatureDifferences fd : newConstructors) {
482: indent().append("<declaration").append(
483: breakdownDeclaration((Method_info) fd
484: .getNewFeature())).append(">").append(
485: fd.getNewDeclaration())
486: .append("</declaration>").eol();
487: }
488:
489: lowerIndent();
490: indent().append("</new-constructors>").eol();
491: }
492:
493: if (newMethods.size() != 0) {
494: indent().append("<new-methods>").eol();
495: raiseIndent();
496:
497: for (FeatureDifferences fd : newMethods) {
498: indent().append("<declaration").append(
499: breakdownDeclaration((Method_info) fd
500: .getNewFeature())).append(">").append(
501: fd.getNewDeclaration())
502: .append("</declaration>").eol();
503: }
504:
505: lowerIndent();
506: indent().append("</new-methods>").eol();
507: }
508:
509: lowerIndent();
510: indent().append("</class>").eol();
511:
512: return super .toString();
513: }
514:
515: private String breakdownDeclaration(Classfile element) {
516: StringBuffer result = new StringBuffer();
517:
518: if (element != null) {
519: if (element.isPublic())
520: result.append(" visibility=\"public\"");
521: if (element.isPackage())
522: result.append(" visibility=\"package\"");
523: if (element.isFinal())
524: result.append(" final=\"yes\"");
525: if (element.isSuper())
526: result.append(" super=\"yes\"");
527: if (element.isSynthetic())
528: result.append(" synthetic=\"yes\"");
529: if (element.isDeprecated())
530: result.append(" deprecated=\"yes\"");
531:
532: result.append(" name=\"").append(element.getClassName())
533: .append("\"");
534:
535: if (element.isInterface()) {
536: result.append(" interface=\"yes\"");
537:
538: result.append(" extends=\"");
539: Iterator i = element.getAllInterfaces().iterator();
540: while (i.hasNext()) {
541: result.append(i.next());
542: if (i.hasNext()) {
543: result.append(", ");
544: }
545: }
546: result.append("\"");
547: } else {
548: if (element.isAbstract())
549: result.append(" abstract=\"yes\"");
550:
551: result.append(" extends=\"").append(
552: element.getSuperclassName()).append("\"");
553:
554: result.append(" implements=\"");
555: Iterator i = element.getAllInterfaces().iterator();
556: while (i.hasNext()) {
557: result.append(i.next());
558: if (i.hasNext()) {
559: result.append(", ");
560: }
561: }
562: result.append("\"");
563: }
564: }
565:
566: return result.toString();
567: }
568:
569: private String breakdownDeclaration(Field_info element) {
570: StringBuffer result = new StringBuffer();
571:
572: if (element != null) {
573: if (element.isPublic())
574: result.append(" visibility=\"public\"");
575: if (element.isProtected())
576: result.append(" visibility=\"protected\"");
577: if (element.isPackage())
578: result.append(" visibility=\"package\"");
579: if (element.isPrivate())
580: result.append(" visibility=\"private\"");
581: if (element.isStatic())
582: result.append(" static=\"yes\"");
583: if (element.isFinal())
584: result.append(" final=\"yes\"");
585: if (element.isVolatile())
586: result.append(" volatile=\"yes\"");
587: if (element.isTransient())
588: result.append(" transient=\"yes\"");
589: if (element.isSynthetic())
590: result.append(" synthetic=\"yes\"");
591: if (element.isDeprecated())
592: result.append(" deprecated=\"yes\"");
593:
594: result.append(" type=\"").append(element.getType()).append(
595: "\"");
596: result.append(" name=\"").append(element.getName()).append(
597: "\"");
598: result.append(" signature=\"").append(
599: element.getSignature()).append("\"");
600: result.append(" full-signature=\"").append(
601: element.getFullSignature()).append("\"");
602:
603: if (element.getConstantValue() != null) {
604: result.append(" value=\"").append(
605: element.getConstantValue().getRawValue())
606: .append("\"");
607: }
608: }
609:
610: return result.toString();
611: }
612:
613: private String breakdownDeclaration(Method_info element) {
614: StringBuffer result = new StringBuffer();
615:
616: if (element != null) {
617: if (element.isPublic())
618: result.append(" visibility=\"public\"");
619: if (element.isProtected())
620: result.append(" visibility=\"protected\"");
621: if (element.isPackage())
622: result.append(" visibility=\"package\"");
623: if (element.isPrivate())
624: result.append(" visibility=\"private\"");
625: if (element.isStatic())
626: result.append(" static=\"yes\"");
627: if (element.isFinal())
628: result.append(" final=\"yes\"");
629: if (element.isSynchronized())
630: result.append(" synchronized=\"yes\"");
631: if (element.isNative())
632: result.append(" native=\"yes\"");
633: if (element.isAbstract())
634: result.append(" abstract=\"yes\"");
635: if (element.isStrict())
636: result.append(" strict=\"yes\"");
637: if (element.isSynthetic())
638: result.append(" synthetic=\"yes\"");
639: if (element.isDeprecated())
640: result.append(" deprecated=\"yes\"");
641:
642: if (!element.getName().equals("<init>")
643: && !element.getName().equals("<clinit>")) {
644: result.append(" return-type=\"").append(
645: element.getReturnType()).append("\"");
646: }
647:
648: result.append(" signature=\"").append(
649: element.getSignature()).append("\"");
650: result.append(" full-signature=\"").append(
651: element.getFullSignature()).append("\"");
652:
653: result.append(" throws=\"");
654: Iterator i = element.getExceptions().iterator();
655: while (i.hasNext()) {
656: result.append(i.next());
657: if (i.hasNext()) {
658: result.append(", ");
659: }
660: }
661: result.append("\"");
662: }
663:
664: return result.toString();
665: }
666:
667: public int compareTo(Object other) {
668: int result = 0;
669:
670: if (other instanceof ClassReport) {
671: result = differences
672: .compareTo(((ClassReport) other).differences);
673: } else {
674: throw new ClassCastException(
675: "Unable to compare ClassReport to "
676: + other.getClass().getName());
677: }
678:
679: return result;
680: }
681: }
|