View Javadoc

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      private Date endDateCutoff = null;
65  
66      /** buffer for the UP statistics (increased number of violations). */
67      private StringBuffer upBuf = new StringBuffer();
68  
69      /** buffer for the DOWN statistics (decreased number of violations). */
70      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      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      public FileStats(final Map types, final String fileSurveyed, final String pathToFile, final Date cutoff) {
95          this.typesSurveyed = types;
96          this.filename = fileSurveyed;
97          this.pathToFile = pathToFile;
98          this.startDateCutoff = new Date(cutoff.getTime());
99      }
100 
101     /**
102      * @return Return filename of this object.
103      */
104     public final String getFileName() {
105         return filename;
106     }
107 
108     /**
109      * @return Return the XML entry for UP movers (increased violations).
110      */
111     public final String getUpXmlResult() {
112         return upBuf.toString();
113     }
114 
115     /**
116      * @return Return the XML entry for DOWN movers (decreased violations).
117      */
118     public final String getDownXmlResult() {
119         return downBuf.toString();
120     }
121 
122     /**
123      * Construct the XML buffers.
124      */
125     public final void constructXML() {
126         Set keys = (Set) typesSurveyed.keySet();
127         Iterator i = keys.iterator();
128 
129         while (i.hasNext()) {
130             Stack s = (Stack) typesSurveyed.get((String) i.next());
131 
132             processFilesResultBeans(s);
133         }
134 
135         if (upBuf.length() > 0) {
136             upBuf.insert(0, "  <file name=\"" + getFileName() + "\" path=\"" + getPathToFile() + "\">" + QALabTags.LINE_END);
137             upBuf.append("  </file>").append(QALabTags.LINE_END);
138         }
139 
140         if (downBuf.length() > 0) {
141             downBuf.insert(0, "  <file name=\"" + getFileName() + "\" path=\"" + getPathToFile() + "\">" + QALabTags.LINE_END);
142             downBuf.append("  </file>").append(QALabTags.LINE_END);
143         }
144     }
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         if (stack.empty()) {
155             return;
156         }
157 
158         // get a result from stack.
159         SingleStat currentResult = (SingleStat) stack.pop();
160 
161         Iterator it = stack.iterator();
162 //        boolean onlyOneResult = !it.hasNext();
163 
164         // set the date of the result.
165         Calendar currentday = Calendar.getInstance();
166         currentday.setTime(getEndDateCutoff());
167         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         if (/*onlyOneResult && */!currentResult.getDate().before(startDateCutoff)
182                 && currentResult.getDate().before(currentday.getTime())) {
183             appendStats(downBuf, currentResult, null);
184         }
185 
186         checkPreviousResults(stack, currentResult, it);
187     }
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         Calendar oneDayBeforeEndCutoff = Calendar.getInstance();
197         oneDayBeforeEndCutoff.setTime(endDateCutoff);
198         oneDayBeforeEndCutoff.add(Calendar.HOUR, -offsetForLastRun);
199 
200         // iterate through the previous results.
201         while (it.hasNext()) {
202             previousResult = (SingleStat) stack.pop();
203 
204             int previousCount = previousResult.getStatValue();
205             final int currentCount = currentResult.getStatValue();
206 
207             // if (previousResult.getDate().before(startDateCutoff)) {
208             // previousCount = 0; // assume 0.
209             // }
210 
211             final int diff = currentCount - previousCount;
212 
213             if (diff > 0) {
214                 handleUp(currentResult, previousResult);
215             } else if (diff < 0) {
216                 handleDown(currentResult, previousResult);
217             } 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                 appendStats(upBuf, null, currentResult);
224             }
225 
226             currentResult = previousResult;
227         }
228         // if the last resul (earliest) falls in the window, we can assume that
229         // it should be part of the UP category. 
230         if (fallInWindow(currentResult)) {
231             appendStats(upBuf, null, currentResult);
232         }
233     }
234 
235     /**
236      * @param currentResult
237      * @param previousResult
238      */
239     private void handleDown(SingleStat currentResult, SingleStat previousResult) {
240         if (fallInWindow(currentResult)) {
241             // there are LESS violations this time round.
242             appendStats(downBuf, previousResult, currentResult);
243         }
244     }
245 
246     /**
247      * @param currentResult
248      * @param previousResult
249      */
250     private void handleUp(SingleStat currentResult, SingleStat previousResult) {
251         if (fallInWindow(currentResult)) {
252             // there are MORE violations this time round.
253             appendStats(upBuf, previousResult, currentResult);
254         }
255 
256     }
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         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         int previousCount = 0;
280 
281         if (previousResult != null) {
282             previousCount = previousResult.getStatValue();
283         }
284 
285         int currentCount = 0;
286 
287         if (currentResult != null) {
288             currentCount = currentResult.getStatValue();
289         }
290 
291         int diff = currentCount - previousCount;
292 
293         if (diff != 0) {
294             buffer.append("   <diff previousrun=\"");
295     
296             if (previousResult != null) {
297                 writeDate(buffer, previousResult);
298             } else {
299                 buffer.append("-");
300             }
301     
302             buffer.append("\" currentrun=\"");
303     
304             if (currentResult != null) {
305                 writeDate(buffer, currentResult);
306                 buffer.append("\" type=\"").append(currentResult.getType());
307             } else {
308                 buffer.append("-");
309                 buffer.append("\" type=\"").append(previousResult.getType());
310             }
311     
312             buffer.append("\" previouserrors=\"");
313     
314             buffer.append(previousCount);
315             buffer.append("\" currenterrors=\"");
316             buffer.append(currentCount);
317             buffer.append("\" diff=\"");
318             buffer.append(diff);
319             buffer.append("\"/>").append(QALabTags.LINE_END);
320         }
321     }
322 
323     /**
324      * @param buffer
325      * @param currentResult
326      */
327     private void writeDate(final StringBuffer buffer, final SingleStat currentResult) {
328         Date date = currentResult.getDate();
329         Calendar cal = Calendar.getInstance();
330         cal.setTime(date);
331 
332         if (0 == cal.get(Calendar.SECOND) && 0 == cal.get(Calendar.MINUTE) && 0 == cal.get(Calendar.HOUR)) {
333             buffer.append(QALabTags.DEFAULT_DATE_FORMAT.format(currentResult.getDate()));
334         } else {
335             buffer.append(QALabTags.DEFAULT_DATETIME_FORMAT.format(currentResult.getDate()));
336         }
337     }
338 
339     /**
340      * @param endDate
341      *            The endDateCutoff to set.
342      */
343     public final void setEndDateCutoff(final Date endDate) {
344         this.endDateCutoff = new Date(endDate.getTime());
345     }
346 
347     /**
348      * @return Returns the endDateCutoff.
349      */
350     public final Date getEndDateCutoff() {
351         return new Date(endDateCutoff.getTime());
352     }
353 
354     /**
355      * @return Returns the pathToFile.
356      */
357     public final String getPathToFile() {
358         return pathToFile;
359     }
360 
361     /**
362      * @param pathToFile
363      *            The pathToFile to set.
364      */
365     public final void setPathToFile(String pathToFile) {
366         this.pathToFile = pathToFile;
367     }
368 
369     public int getOffsetForLastRun() {
370         return offsetForLastRun;
371     }
372 
373     public void setOffsetForLastRun(int offsetForLastRun) {
374         this.offsetForLastRun = offsetForLastRun;
375     }
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  */