Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FileStats |
|
| 2.0555555555555554;2.056 |
1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // | |
3 | // ObjectLab is sponsoring QALab | |
4 | // | |
5 | // Based in London, we are world leaders in the design and development | |
6 | // of bespoke applications for the Securities Financing markets. | |
7 | // | |
8 | // <a href="http://www.objectlab.co.uk/open">Click here to learn more</a> | |
9 | // ___ _ _ _ _ _ | |
10 | // / _ \| |__ (_) ___ ___| |_| | __ _| |__ | |
11 | // | | | | '_ \| |/ _ \/ __| __| | / _` | '_ \ | |
12 | // | |_| | |_) | | __/ (__| |_| |__| (_| | |_) | | |
13 | // \___/|_.__// |\___|\___|\__|_____\__,_|_.__/ | |
14 | // |__/ | |
15 | // | |
16 | // http://www.ObjectLab.co.uk | |
17 | // --------------------------------------------------------------------------- | |
18 | // | |
19 | //QALab is released under the GNU General Public License. | |
20 | // | |
21 | //QALab: Collects QA Statistics from your build over time. | |
22 | //2005+, ObjectLab Ltd | |
23 | // | |
24 | //This library is free software; you can redistribute it and/or | |
25 | //modify it under the terms of the GNU General Public | |
26 | //License as published by the Free Software Foundation; either | |
27 | //version 2.1 of the License, or (at your option) any later version. | |
28 | // | |
29 | //This library is distributed in the hope that it will be useful, | |
30 | //but WITHOUT ANY WARRANTY; without even the implied warranty of | |
31 | //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
32 | //General Public License for more details. | |
33 | // | |
34 | //You should have received a copy of the GNU General Public | |
35 | //License along with this library; if not, write to the Free Software | |
36 | //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
37 | // | |
38 | //////////////////////////////////////////////////////////////////////////////// | |
39 | package net.objectlab.qalab.parser; | |
40 | ||
41 | import net.objectlab.qalab.util.QALabTags; | |
42 | ||
43 | import java.util.Calendar; | |
44 | import java.util.Date; | |
45 | import java.util.Iterator; | |
46 | import java.util.Map; | |
47 | import java.util.Set; | |
48 | import java.util.Stack; | |
49 | ||
50 | /** | |
51 | * As part of the up/down movers task, this class contains info about a given | |
52 | * file. | |
53 | * | |
54 | * @author Paramjit Rehinsi | |
55 | * @version $Revision: 226 $ | |
56 | */ | |
57 | public class FileStats { | |
58 | private static final int ONE_DAY = 24; | |
59 | ||
60 | /** the date cut-off, do not include stats if before that date. */ | |
61 | private Date startDateCutoff; | |
62 | ||
63 | /** the end date cut-off, do not include stats if after that date. */ | |
64 | 252 | private Date endDateCutoff = null; |
65 | ||
66 | /** buffer for the UP statistics (increased number of violations). */ | |
67 | 252 | private StringBuffer upBuf = new StringBuffer(); |
68 | ||
69 | /** buffer for the DOWN statistics (decreased number of violations). */ | |
70 | 252 | private StringBuffer downBuf = new StringBuffer(); |
71 | ||
72 | /** file name (typically a .java file). */ | |
73 | private String filename; | |
74 | ||
75 | /** path to file. */ | |
76 | private String pathToFile; | |
77 | ||
78 | /** type surveyed (checkstyle|findbugs|simian|pmd). */ | |
79 | private Map typesSurveyed; | |
80 | ||
81 | /** offset in hours to determine if the stat has fallen to 0 over the last n hours | |
82 | * from the endDateCutoff. | |
83 | */ | |
84 | 252 | private int offsetForLastRun = ONE_DAY; |
85 | ||
86 | /** | |
87 | * @param types | |
88 | * the types surveyed. | |
89 | * @param fileSurveyed | |
90 | * the file name surveyed. | |
91 | * @param cutoff | |
92 | * earliest date to take into account. | |
93 | */ | |
94 | 252 | public FileStats(final Map types, final String fileSurveyed, final String pathToFile, final Date cutoff) { |
95 | 252 | this.typesSurveyed = types; |
96 | 252 | this.filename = fileSurveyed; |
97 | 252 | this.pathToFile = pathToFile; |
98 | 252 | this.startDateCutoff = new Date(cutoff.getTime()); |
99 | 252 | } |
100 | ||
101 | /** | |
102 | * @return Return filename of this object. | |
103 | */ | |
104 | public final String getFileName() { | |
105 | 114 | return filename; |
106 | } | |
107 | ||
108 | /** | |
109 | * @return Return the XML entry for UP movers (increased violations). | |
110 | */ | |
111 | public final String getUpXmlResult() { | |
112 | 252 | return upBuf.toString(); |
113 | } | |
114 | ||
115 | /** | |
116 | * @return Return the XML entry for DOWN movers (decreased violations). | |
117 | */ | |
118 | public final String getDownXmlResult() { | |
119 | 252 | return downBuf.toString(); |
120 | } | |
121 | ||
122 | /** | |
123 | * Construct the XML buffers. | |
124 | */ | |
125 | public final void constructXML() { | |
126 | 252 | Set keys = (Set) typesSurveyed.keySet(); |
127 | 252 | Iterator i = keys.iterator(); |
128 | ||
129 | 543 | while (i.hasNext()) { |
130 | 291 | Stack s = (Stack) typesSurveyed.get((String) i.next()); |
131 | ||
132 | 291 | processFilesResultBeans(s); |
133 | 291 | } |
134 | ||
135 | 252 | if (upBuf.length() > 0) { |
136 | 60 | upBuf.insert(0, " <file name=\"" + getFileName() + "\" path=\"" + getPathToFile() + "\">" + QALabTags.LINE_END); |
137 | 60 | upBuf.append(" </file>").append(QALabTags.LINE_END); |
138 | } | |
139 | ||
140 | 252 | if (downBuf.length() > 0) { |
141 | 54 | downBuf.insert(0, " <file name=\"" + getFileName() + "\" path=\"" + getPathToFile() + "\">" + QALabTags.LINE_END); |
142 | 54 | downBuf.append(" </file>").append(QALabTags.LINE_END); |
143 | } | |
144 | 252 | } |
145 | ||
146 | /** | |
147 | * Build the XML string depending on whether differences have occured since | |
148 | * the cutoff. | |
149 | * | |
150 | * @param stack | |
151 | * each result set in a stack from cutoff. | |
152 | */ | |
153 | private void processFilesResultBeans(final Stack stack) { | |
154 | 291 | if (stack.empty()) { |
155 | 147 | return; |
156 | } | |
157 | ||
158 | // get a result from stack. | |
159 | 144 | SingleStat currentResult = (SingleStat) stack.pop(); |
160 | ||
161 | 144 | Iterator it = stack.iterator(); |
162 | // boolean onlyOneResult = !it.hasNext(); | |
163 | ||
164 | // set the date of the result. | |
165 | 144 | Calendar currentday = Calendar.getInstance(); |
166 | 144 | currentday.setTime(getEndDateCutoff()); |
167 | 144 | currentday.add(Calendar.HOUR, -offsetForLastRun); |
168 | ||
169 | // new result -> gone UP! | |
170 | // BUT only if the result is not BEFORE 1 day from the end result | |
171 | // (otherwise we assume that the has been another run which reduced it | |
172 | // to 0, therefore it would not have gone up. | |
173 | // if (onlyOneResult && fallInWindow(currentResult) | |
174 | /** && !currentResult.getDate().before(currentday.getTime()) */ | |
175 | // ) { | |
176 | // appendStats(upBuf, null, currentResult); | |
177 | // } | |
178 | ||
179 | // if the result set is after the cutoff and less than end-1 then | |
180 | // it means that we do NOT have a result for this guy on end | |
181 | 144 | if (/*onlyOneResult && */!currentResult.getDate().before(startDateCutoff) |
182 | && currentResult.getDate().before(currentday.getTime())) { | |
183 | 30 | appendStats(downBuf, currentResult, null); |
184 | } | |
185 | ||
186 | 144 | checkPreviousResults(stack, currentResult, it); |
187 | 144 | } |
188 | ||
189 | /** | |
190 | * @param stack | |
191 | * @param currentResult | |
192 | * @param it | |
193 | */ | |
194 | private void checkPreviousResults(final Stack stack, SingleStat currentResult, Iterator it) { | |
195 | SingleStat previousResult; | |
196 | 144 | Calendar oneDayBeforeEndCutoff = Calendar.getInstance(); |
197 | 144 | oneDayBeforeEndCutoff.setTime(endDateCutoff); |
198 | 144 | oneDayBeforeEndCutoff.add(Calendar.HOUR, -offsetForLastRun); |
199 | ||
200 | // iterate through the previous results. | |
201 | 624 | while (it.hasNext()) { |
202 | 480 | previousResult = (SingleStat) stack.pop(); |
203 | ||
204 | 480 | int previousCount = previousResult.getStatValue(); |
205 | 480 | final int currentCount = currentResult.getStatValue(); |
206 | ||
207 | // if (previousResult.getDate().before(startDateCutoff)) { | |
208 | // previousCount = 0; // assume 0. | |
209 | // } | |
210 | ||
211 | 480 | final int diff = currentCount - previousCount; |
212 | ||
213 | 480 | if (diff > 0) { |
214 | 36 | handleUp(currentResult, previousResult); |
215 | 36 | } else if (diff < 0) { |
216 | 48 | handleDown(currentResult, previousResult); |
217 | 48 | } else if (diff == 0 && fallInWindow(currentResult) |
218 | && !currentResult.getDate().before(oneDayBeforeEndCutoff.getTime()) | |
219 | && !previousResult.getDate().after(startDateCutoff)) { | |
220 | // this is the case where we may have had the same number of | |
221 | // violation outside the window in the past but this should | |
222 | // count as a NEW violation as it has come back. | |
223 | 0 | appendStats(upBuf, null, currentResult); |
224 | } | |
225 | ||
226 | 480 | currentResult = previousResult; |
227 | 480 | } |
228 | // if the last resul (earliest) falls in the window, we can assume that | |
229 | // it should be part of the UP category. | |
230 | 144 | if (fallInWindow(currentResult)) { |
231 | 66 | appendStats(upBuf, null, currentResult); |
232 | } | |
233 | 144 | } |
234 | ||
235 | /** | |
236 | * @param currentResult | |
237 | * @param previousResult | |
238 | */ | |
239 | private void handleDown(SingleStat currentResult, SingleStat previousResult) { | |
240 | 48 | if (fallInWindow(currentResult)) { |
241 | // there are LESS violations this time round. | |
242 | 33 | appendStats(downBuf, previousResult, currentResult); |
243 | } | |
244 | 48 | } |
245 | ||
246 | /** | |
247 | * @param currentResult | |
248 | * @param previousResult | |
249 | */ | |
250 | private void handleUp(SingleStat currentResult, SingleStat previousResult) { | |
251 | 36 | if (fallInWindow(currentResult)) { |
252 | // there are MORE violations this time round. | |
253 | 30 | appendStats(upBuf, previousResult, currentResult); |
254 | } | |
255 | ||
256 | 36 | } |
257 | ||
258 | /** | |
259 | * return true if the stat falls in the time window. | |
260 | * | |
261 | * @param stat | |
262 | * @return | |
263 | */ | |
264 | private boolean fallInWindow(SingleStat stat) { | |
265 | 624 | return !stat.getDate().before(startDateCutoff) && !stat.getDate().after(endDateCutoff); |
266 | } | |
267 | ||
268 | /** | |
269 | * Append statistics to up or down buffer. | |
270 | * | |
271 | * @param buffer | |
272 | * the up or down buffer | |
273 | * @param previousResult | |
274 | * can be null (ie 0) | |
275 | * @param currentResult | |
276 | * can be null (ie 0) | |
277 | */ | |
278 | private void appendStats(final StringBuffer buffer, final SingleStat previousResult, final SingleStat currentResult) { | |
279 | 159 | int previousCount = 0; |
280 | ||
281 | 159 | if (previousResult != null) { |
282 | 93 | previousCount = previousResult.getStatValue(); |
283 | } | |
284 | ||
285 | 159 | int currentCount = 0; |
286 | ||
287 | 159 | if (currentResult != null) { |
288 | 129 | currentCount = currentResult.getStatValue(); |
289 | } | |
290 | ||
291 | 159 | int diff = currentCount - previousCount; |
292 | ||
293 | 159 | if (diff != 0) { |
294 | 159 | buffer.append(" <diff previousrun=\""); |
295 | ||
296 | 159 | if (previousResult != null) { |
297 | 93 | writeDate(buffer, previousResult); |
298 | 93 | } else { |
299 | 66 | buffer.append("-"); |
300 | } | |
301 | ||
302 | 159 | buffer.append("\" currentrun=\""); |
303 | ||
304 | 159 | if (currentResult != null) { |
305 | 129 | writeDate(buffer, currentResult); |
306 | 129 | buffer.append("\" type=\"").append(currentResult.getType()); |
307 | 129 | } else { |
308 | 30 | buffer.append("-"); |
309 | 30 | buffer.append("\" type=\"").append(previousResult.getType()); |
310 | } | |
311 | ||
312 | 159 | buffer.append("\" previouserrors=\""); |
313 | ||
314 | 159 | buffer.append(previousCount); |
315 | 159 | buffer.append("\" currenterrors=\""); |
316 | 159 | buffer.append(currentCount); |
317 | 159 | buffer.append("\" diff=\""); |
318 | 159 | buffer.append(diff); |
319 | 159 | buffer.append("\"/>").append(QALabTags.LINE_END); |
320 | } | |
321 | 159 | } |
322 | ||
323 | /** | |
324 | * @param buffer | |
325 | * @param currentResult | |
326 | */ | |
327 | private void writeDate(final StringBuffer buffer, final SingleStat currentResult) { | |
328 | 222 | Date date = currentResult.getDate(); |
329 | 222 | Calendar cal = Calendar.getInstance(); |
330 | 222 | cal.setTime(date); |
331 | ||
332 | 222 | if (0 == cal.get(Calendar.SECOND) && 0 == cal.get(Calendar.MINUTE) && 0 == cal.get(Calendar.HOUR)) { |
333 | 0 | buffer.append(QALabTags.DEFAULT_DATE_FORMAT.format(currentResult.getDate())); |
334 | 0 | } else { |
335 | 222 | buffer.append(QALabTags.DEFAULT_DATETIME_FORMAT.format(currentResult.getDate())); |
336 | } | |
337 | 222 | } |
338 | ||
339 | /** | |
340 | * @param endDate | |
341 | * The endDateCutoff to set. | |
342 | */ | |
343 | public final void setEndDateCutoff(final Date endDate) { | |
344 | 252 | this.endDateCutoff = new Date(endDate.getTime()); |
345 | 252 | } |
346 | ||
347 | /** | |
348 | * @return Returns the endDateCutoff. | |
349 | */ | |
350 | public final Date getEndDateCutoff() { | |
351 | 144 | return new Date(endDateCutoff.getTime()); |
352 | } | |
353 | ||
354 | /** | |
355 | * @return Returns the pathToFile. | |
356 | */ | |
357 | public final String getPathToFile() { | |
358 | 114 | return pathToFile; |
359 | } | |
360 | ||
361 | /** | |
362 | * @param pathToFile | |
363 | * The pathToFile to set. | |
364 | */ | |
365 | public final void setPathToFile(String pathToFile) { | |
366 | 0 | this.pathToFile = pathToFile; |
367 | 0 | } |
368 | ||
369 | public int getOffsetForLastRun() { | |
370 | 0 | return offsetForLastRun; |
371 | } | |
372 | ||
373 | public void setOffsetForLastRun(int offsetForLastRun) { | |
374 | 252 | this.offsetForLastRun = offsetForLastRun; |
375 | 252 | } |
376 | } | |
377 | /* | |
378 | * ObjectLab is sponsoring QALab | |
379 | * | |
380 | * Based in London, we are world leaders in the design and development | |
381 | * of bespoke applications for the securities financing markets. | |
382 | * | |
383 | * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a> | |
384 | * ___ _ _ _ _ _ | |
385 | * / _ \| |__ (_) ___ ___| |_| | __ _| |__ | |
386 | * | | | | '_ \| |/ _ \/ __| __| | / _` | '_ \ | |
387 | * | |_| | |_) | | __/ (__| |_| |__| (_| | |_) | | |
388 | * \___/|_.__// |\___|\___|\__|_____\__,_|_.__/ | |
389 | * |__/ | |
390 | * | |
391 | * www.ObjectLab.co.uk | |
392 | */ |