1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.clirr.core;
21
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import net.sf.clirr.core.internal.ApiDiffDispatcher;
27 import net.sf.clirr.core.internal.ClassChangeCheck;
28 import net.sf.clirr.core.internal.CoIterator;
29 import net.sf.clirr.core.internal.NameComparator;
30 import net.sf.clirr.core.internal.checks.ClassHierarchyCheck;
31 import net.sf.clirr.core.internal.checks.ClassModifierCheck;
32 import net.sf.clirr.core.internal.checks.ClassScopeCheck;
33 import net.sf.clirr.core.internal.checks.FieldSetCheck;
34 import net.sf.clirr.core.internal.checks.GenderChangeCheck;
35 import net.sf.clirr.core.internal.checks.InterfaceSetCheck;
36 import net.sf.clirr.core.internal.checks.MethodSetCheck;
37 import net.sf.clirr.core.spi.JavaType;
38 import net.sf.clirr.core.spi.Scope;
39
40 /***
41 * This is the main class to be used by Clirr frontends,
42 * it implements the checking functionality of Clirr.
43 * Frontends can create an instance of this class
44 * and register themselves as DiffListeners, they are then
45 * informed whenever an API change is detected by the
46 * reportDiffs method.
47 *
48 * @author lkuehne
49 */
50 public final class Checker implements ApiDiffDispatcher
51 {
52 private static final Message MSG_CLASS_ADDED = new Message(8000);
53 private static final Message MSG_CLASS_REMOVED = new Message(8001);
54
55 private List listeners = new ArrayList();
56
57 private List classChecks = new ArrayList();
58
59 private ScopeSelector scopeSelector = new ScopeSelector();
60
61 /***
62 * Package visible constructor for unit testing.
63 */
64 Checker(ClassChangeCheck ccc)
65 {
66 if (ccc != null)
67 {
68 classChecks.add(ccc);
69 }
70 }
71
72 /***
73 * Creates a new Checker.
74 */
75 public Checker()
76 {
77 classChecks.add(new ClassScopeCheck(this, scopeSelector));
78 classChecks.add(new GenderChangeCheck(this));
79 classChecks.add(new ClassModifierCheck(this));
80 classChecks.add(new InterfaceSetCheck(this));
81 classChecks.add(new ClassHierarchyCheck(this));
82 classChecks.add(new FieldSetCheck(this, scopeSelector));
83 classChecks.add(new MethodSetCheck(this, scopeSelector));
84 }
85
86 public ScopeSelector getScopeSelector()
87 {
88 return scopeSelector;
89 }
90
91 public void addDiffListener(DiffListener listener)
92 {
93 listeners.add(listener);
94 }
95
96 private void fireStart()
97 {
98 for (Iterator it = listeners.iterator(); it.hasNext();)
99 {
100 DiffListener diffListener = (DiffListener) it.next();
101 diffListener.start();
102 }
103 }
104
105 private void fireStop()
106 {
107 for (Iterator it = listeners.iterator(); it.hasNext();)
108 {
109 DiffListener diffListener = (DiffListener) it.next();
110 diffListener.stop();
111 }
112 }
113
114 public void fireDiff(ApiDifference diff)
115 {
116 for (Iterator it = listeners.iterator(); it.hasNext();)
117 {
118 DiffListener diffListener = (DiffListener) it.next();
119 diffListener.reportDiff(diff);
120 }
121 }
122
123 /***
124 * Checks two sets of classes for api changes and reports
125 * them to the DiffListeners.
126 * @param compatibilityBaseline the classes that form the
127 * compatibility baseline to check against
128 * @param currentVersion the classes that are checked for
129 * compatibility with compatibilityBaseline
130 */
131 public void reportDiffs(
132 JavaType[] compatibilityBaseline, JavaType[] currentVersion)
133 throws CheckerException
134 {
135 fireStart();
136 runClassChecks(compatibilityBaseline, currentVersion);
137 fireStop();
138 }
139
140 private void runClassChecks(
141 JavaType[] compat, JavaType[] current)
142 throws CheckerException
143 {
144 CoIterator iter = new CoIterator(
145 new NameComparator(), compat, current);
146
147 while (iter.hasNext())
148 {
149 iter.next();
150
151 JavaType compatBaselineClass = (JavaType) iter.getLeft();
152 JavaType currentClass = (JavaType) iter.getRight();
153
154 if (compatBaselineClass == null)
155 {
156 if (!scopeSelector.isSelected(currentClass.getEffectiveScope()))
157 {
158 continue;
159 }
160 final String className = currentClass.getName();
161 final ApiDifference diff =
162 new ApiDifference(
163 MSG_CLASS_ADDED, Severity.INFO, className,
164 null, null, null);
165 fireDiff(diff);
166 }
167 else if (currentClass == null)
168 {
169 final Scope classScope = compatBaselineClass.getEffectiveScope();
170 if (!scopeSelector.isSelected(classScope))
171 {
172 continue;
173 }
174 final String className = compatBaselineClass.getName();
175 final Severity severity = classScope.isLessVisibleThan(
176 Scope.PROTECTED) ? Severity.INFO : Severity.ERROR;
177 final ApiDifference diff =
178 new ApiDifference(
179 MSG_CLASS_REMOVED, severity, className,
180 null, null, null);
181 fireDiff(diff);
182 }
183 else
184 {
185
186 boolean continueTesting = true;
187 for (Iterator it = classChecks.iterator(); it.hasNext() && continueTesting;)
188 {
189 ClassChangeCheck classChangeCheck = (ClassChangeCheck) it.next();
190 continueTesting = classChangeCheck.check(
191 compatBaselineClass, currentClass);
192 }
193 }
194 }
195 }
196 }