001: //////////////////////////////////////////////////////////////////////////////
002: // Clirr: compares two versions of a java library for binary compatibility
003: // Copyright (C) 2003 - 2005 Lars Kühne
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: //////////////////////////////////////////////////////////////////////////////
019:
020: package net.sf.clirr.core;
021:
022: import java.util.ArrayList;
023: import java.util.Iterator;
024: import java.util.List;
025:
026: import net.sf.clirr.core.internal.ApiDiffDispatcher;
027: import net.sf.clirr.core.internal.ClassChangeCheck;
028: import net.sf.clirr.core.internal.CoIterator;
029: import net.sf.clirr.core.internal.NameComparator;
030: import net.sf.clirr.core.internal.checks.ClassHierarchyCheck;
031: import net.sf.clirr.core.internal.checks.ClassModifierCheck;
032: import net.sf.clirr.core.internal.checks.ClassScopeCheck;
033: import net.sf.clirr.core.internal.checks.FieldSetCheck;
034: import net.sf.clirr.core.internal.checks.GenderChangeCheck;
035: import net.sf.clirr.core.internal.checks.InterfaceSetCheck;
036: import net.sf.clirr.core.internal.checks.MethodSetCheck;
037: import net.sf.clirr.core.spi.JavaType;
038: import net.sf.clirr.core.spi.Scope;
039:
040: /**
041: * This is the main class to be used by Clirr frontends,
042: * it implements the checking functionality of Clirr.
043: * Frontends can create an instance of this class
044: * and register themselves as DiffListeners, they are then
045: * informed whenever an API change is detected by the
046: * reportDiffs method.
047: *
048: * @author lkuehne
049: */
050: public final class Checker implements ApiDiffDispatcher {
051: private static final Message MSG_CLASS_ADDED = new Message(8000);
052: private static final Message MSG_CLASS_REMOVED = new Message(8001);
053:
054: private List listeners = new ArrayList();
055:
056: private List classChecks = new ArrayList();
057:
058: private ScopeSelector scopeSelector = new ScopeSelector();
059:
060: /**
061: * Package visible constructor for unit testing.
062: */
063: Checker(ClassChangeCheck ccc) {
064: if (ccc != null) {
065: classChecks.add(ccc);
066: }
067: }
068:
069: /**
070: * Creates a new Checker.
071: */
072: public Checker() {
073: classChecks.add(new ClassScopeCheck(this , scopeSelector));
074: classChecks.add(new GenderChangeCheck(this ));
075: classChecks.add(new ClassModifierCheck(this ));
076: classChecks.add(new InterfaceSetCheck(this ));
077: classChecks.add(new ClassHierarchyCheck(this ));
078: classChecks.add(new FieldSetCheck(this , scopeSelector));
079: classChecks.add(new MethodSetCheck(this , scopeSelector));
080: }
081:
082: public ScopeSelector getScopeSelector() {
083: return scopeSelector;
084: }
085:
086: public void addDiffListener(DiffListener listener) {
087: listeners.add(listener);
088: }
089:
090: private void fireStart() {
091: for (Iterator it = listeners.iterator(); it.hasNext();) {
092: DiffListener diffListener = (DiffListener) it.next();
093: diffListener.start();
094: }
095: }
096:
097: private void fireStop() {
098: for (Iterator it = listeners.iterator(); it.hasNext();) {
099: DiffListener diffListener = (DiffListener) it.next();
100: diffListener.stop();
101: }
102: }
103:
104: public void fireDiff(ApiDifference diff) {
105: for (Iterator it = listeners.iterator(); it.hasNext();) {
106: DiffListener diffListener = (DiffListener) it.next();
107: diffListener.reportDiff(diff);
108: }
109: }
110:
111: /**
112: * Checks two sets of classes for api changes and reports
113: * them to the DiffListeners.
114: * @param compatibilityBaseline the classes that form the
115: * compatibility baseline to check against
116: * @param currentVersion the classes that are checked for
117: * compatibility with compatibilityBaseline
118: */
119: public void reportDiffs(JavaType[] compatibilityBaseline,
120: JavaType[] currentVersion) throws CheckerException {
121: fireStart();
122: runClassChecks(compatibilityBaseline, currentVersion);
123: fireStop();
124: }
125:
126: private void runClassChecks(JavaType[] compat, JavaType[] current)
127: throws CheckerException {
128: CoIterator iter = new CoIterator(new NameComparator(), compat,
129: current);
130:
131: while (iter.hasNext()) {
132: iter.next();
133:
134: JavaType compatBaselineClass = (JavaType) iter.getLeft();
135: JavaType currentClass = (JavaType) iter.getRight();
136:
137: if (compatBaselineClass == null) {
138: if (!scopeSelector.isSelected(currentClass
139: .getEffectiveScope())) {
140: continue;
141: }
142: final String className = currentClass.getName();
143: final ApiDifference diff = new ApiDifference(
144: MSG_CLASS_ADDED, Severity.INFO, className,
145: null, null, null);
146: fireDiff(diff);
147: } else if (currentClass == null) {
148: final Scope classScope = compatBaselineClass
149: .getEffectiveScope();
150: if (!scopeSelector.isSelected(classScope)) {
151: continue;
152: }
153: final String className = compatBaselineClass.getName();
154: final Severity severity = classScope
155: .isLessVisibleThan(Scope.PROTECTED) ? Severity.INFO
156: : Severity.ERROR;
157: final ApiDifference diff = new ApiDifference(
158: MSG_CLASS_REMOVED, severity, className, null,
159: null, null);
160: fireDiff(diff);
161: } else {
162: // class is available in both releases
163: boolean continueTesting = true;
164: for (Iterator it = classChecks.iterator(); it.hasNext()
165: && continueTesting;) {
166: ClassChangeCheck classChangeCheck = (ClassChangeCheck) it
167: .next();
168: continueTesting = classChangeCheck.check(
169: compatBaselineClass, currentClass);
170: }
171: }
172: }
173: }
174: }
|