1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package net.objectlab.qalab.parser;
40
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.Reader;
44 import java.io.StringReader;
45 import java.math.BigDecimal;
46
47 import net.objectlab.qalab.util.FilenameUtil;
48 import net.objectlab.qalab.util.Util;
49
50 import org.xml.sax.Attributes;
51 import org.xml.sax.InputSource;
52 import org.xml.sax.SAXException;
53
54 /**
55 * This class is able to read the XML output from Cobertura (LINE INFORMATION)
56 * and integrate the violation results into our "qalab" xml format.
57 *
58 * @author Benoit Xhenseval
59 * @version $Revision$
60 */
61 public class CoberturaLineStatMerge extends BaseStatMerge {
62 private static final String COBERTURA_LINE = "cobertura-line";
63
64 private int totalLineRate = 0;
65
66 private int totalBranchRate = 0;
67
68 private boolean skipCurrentElement = false;
69
70
71
72
73 /**
74 * @return cobertura-line
75 */
76 public String getType() {
77 return COBERTURA_LINE;
78 }
79
80 protected final String getSummaryTag() {
81 return "coverage";
82 }
83
84 private Object getFileTag() {
85 return "class";
86 }
87
88 /**
89 *
90 * @return "filename" the attribute tag for file.
91 */
92 private String getFileNameAttribute() {
93 return "filename";
94 }
95
96 /**
97 * At the start of a new element, capture the filename and if the element is
98 * a result one, create a SingleStat to store for the given type.
99 *
100 * @param ignoreNamespaceURI
101 * ignore (present for interface implementation).
102 * @param localname
103 * name of the current element.
104 * @param qualifiedname
105 * element name.
106 * @param attrs
107 * the XML attribute of the current element.
108 * @throws SAXException
109 * any SAX issue
110 */
111 public final void startElement(final String ignoreNamespaceURI,
112 final String localname, final String qualifiedname,
113 final Attributes attrs) throws SAXException {
114 String local = localname;
115
116 if ("".equals(local)) {
117 local = qualifiedname;
118 }
119
120
121
122
123
124 if (getSummaryTag().equals(local)) {
125 final String lineRate = Util.getAttributeValue(attrs, "line-rate",
126 isQuiet(), getTaskLogger());
127 final String branchRate = Util.getAttributeValue(attrs,
128 "branch-rate", isQuiet(), getTaskLogger());
129 totalLineRate = new BigDecimal(lineRate).movePointRight(2)
130 .intValue();
131 totalBranchRate = new BigDecimal(branchRate).movePointRight(2)
132 .intValue();
133 } else if (getFileTag().equals(local)) {
134
135 String className = Util.getAttributeValue(attrs, "name", isQuiet(),
136 getTaskLogger());
137
138 if (className != null && className.indexOf('$') > 0) {
139 skipCurrentElement = true;
140 return;
141 }
142
143
144 resetFileStatistics();
145 incrementFileCount(1);
146 setFileName(attrs);
147
148 final String lineRate = Util.getAttributeValue(attrs, "line-rate",
149 isQuiet(), getTaskLogger());
150 final String branchRate = Util.getAttributeValue(attrs,
151 "branch-rate", isQuiet(), getTaskLogger());
152
153 if (!isQuiet()) {
154 getTaskLogger().log(
155 "lineRate=" + lineRate + " branchRate=" + branchRate);
156 }
157
158 if (getType().equals(COBERTURA_LINE)) {
159 int lineAsPercent = new BigDecimal(lineRate).movePointRight(2)
160 .intValue();
161 addFileStatistics(lineAsPercent);
162 } else {
163
164 int lineAsPercent = new BigDecimal(branchRate)
165 .movePointRight(2).intValue();
166 addFileStatistics(lineAsPercent);
167 }
168 }
169 }
170
171 /**
172 * At the end of an element, check if it is a file one and add the results
173 * found.
174 *
175 * @param ignoreNamespaceURI
176 * ignore (present for interface implementation).
177 * @param ignoreSimplename
178 * ignore (present for interface implementation).
179 * @param qualifiedname
180 * the name of the element.
181 * @throws SAXException
182 * any SAX issue
183 */
184 public final void endElement(final String ignoreNamespaceURI,
185 final String ignoreSimplename, final String qualifiedname)
186 throws SAXException {
187
188
189
190
191 if (getFileTag().equals(qualifiedname)) {
192 if (!skipCurrentElement) {
193 addNewResults();
194 } else {
195 skipCurrentElement = false;
196 }
197 }
198 }
199
200 /**
201 * set the file name from the attributes from Findbugs XML.
202 *
203 * @param att
204 * xml attributes
205 */
206 protected void setFileName(final Attributes att) {
207 String fileName = Util.getAttributeValue(att, getFileNameAttribute(),
208 isQuiet(), getTaskLogger());
209
210
211
212
213
214 fileName = FilenameUtil.trimFilename(fileName, getSrcDir());
215
216 if (!isQuiet()) {
217 getTaskLogger().log(
218 "setCurrentFileName FILE [" + fileName + "] srcDir ["
219 + getSrcDir() + "]");
220 }
221
222 setCurrentFile(fileName);
223 }
224
225 /**
226 * For Cobertura the total statistics is the average of coverage, ie sum of
227 * all percentages divided by the TOTAL number of files (ie we do not report
228 * ZERO % coverage but they should count).
229 */
230 public int getTotalStatistics() {
231 if (getType().equals(COBERTURA_LINE)) {
232 return totalLineRate;
233 } else {
234 return totalBranchRate;
235 }
236 }
237
238 /**
239 * This is required to get rid of the SYSTEM DTD otherwise one cannot parse
240 * coverage.xml behind most firewalls or offline.
241 */
242 protected InputSource preProcessSource(InputSource source) {
243 StringBuffer buf = new StringBuffer();
244 InputStream reader = source.getByteStream();
245 int i = -1;
246
247
248 if (reader != null) {
249 do {
250 try {
251 i = reader.read();
252 } catch (IOException e) {
253 getTaskLogger().log(e.toString());
254 }
255 buf.append((char) i);
256 } while (i >= 0);
257 } else {
258 Reader rd = source.getCharacterStream();
259 do {
260 try {
261 i = rd.read();
262 } catch (IOException e) {
263 getTaskLogger().log(e.toString());
264 }
265 buf.append((char) i);
266 } while (i >= 0);
267 }
268 int idx = buf.indexOf("<coverage");
269 if (idx >= 0) {
270 buf = buf.delete(0, idx);
271 }
272
273 return new InputSource(new StringReader(buf.toString()));
274 }
275 }
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291