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 java.io.IOException;
42  import java.text.ParseException;
43  import java.util.Calendar;
44  import java.util.Date;
45  
46  import javax.xml.parsers.ParserConfigurationException;
47  import javax.xml.parsers.SAXParser;
48  import javax.xml.parsers.SAXParserFactory;
49  
50  import net.objectlab.qalab.interfaces.QALabExporter;
51  import net.objectlab.qalab.util.QALabTags;
52  import net.objectlab.qalab.util.TaskLogger;
53  
54  import org.xml.sax.EntityResolver;
55  import org.xml.sax.InputSource;
56  import org.xml.sax.SAXException;
57  import org.xml.sax.helpers.DefaultHandler;
58  
59  /**
60   * This class abstract some methods used by all Stat Mergers being for
61   * Checkstyle, pmd, findbugs or Simian. This class implements some SAX callbacks
62   * for parsing the input statistics.
63   * 
64   * @author Benoit Xhenseval
65   * @version $Revision: 187 $
66   */
67  public abstract class BaseStatMerge extends DefaultHandler implements
68          StatMerger {
69      // ~ Instance fields
70      // ------------------------------------------------------------------------
71  
72      /** total Statistics. * */
73      private int totalStatistics = 0;
74  
75      /** count the number of files. * */
76      private int fileCount = 0;
77  
78      /** statistics for given file. * */
79      private int fileStatistics = 0;
80  
81      /** keep the current file name. * */
82      private String currentFile = null;
83  
84      /** if true, no debug information is logged. * */
85      private boolean quiet = true;
86  
87      /** given implementation for the logger. * */
88      private TaskLogger taskLogger = null;
89  
90      /** The directory for source code. * */
91      private String srcDir;
92  
93      /** exporter for the statistics. */
94      private QALabExporter exporter = null;
95  
96      /** timestamp to use for Merge. */
97      private Date mergerTimeStamp;
98  
99      /** timestamp as date only. */
100     private boolean timeStampAsDateOnly = true;
101 
102     // ~ Methods
103     // ------------------------------------------------------------------------
104 
105     /**
106      * @param theFile
107      *            the current file for which the stats are processed.
108      */
109     public final void setCurrentFile(final String theFile) {
110         this.currentFile = theFile;
111     }
112 
113     /**
114      * @return true means that no debug info is logged.
115      */
116     public final boolean isQuiet() {
117         return quiet;
118     }
119 
120     /**
121      * @param noLog
122      *            true if no log required.
123      */
124     public final void setQuiet(final boolean noLog) {
125         this.quiet = noLog;
126     }
127 
128     /**
129      * set the logger to use.
130      * 
131      * @param task
132      *            the logger.
133      */
134     public final void setTaskLogger(final TaskLogger task) {
135         this.taskLogger = task;
136     }
137 
138     /**
139      * @return logger to use if not quiet.
140      */
141     protected final TaskLogger getTaskLogger() {
142         return taskLogger;
143     }
144 
145     /**
146      * this will be used to truncate machine specific path.
147      * 
148      * @param directory
149      *            the source directory.
150      */
151     public final void setSrcDir(final String directory) {
152         srcDir = directory.replace('\\', '/');
153     }
154 
155     /**
156      * @return the source directory
157      */
158     public final String getSrcDir() {
159         return srcDir;
160     }
161 
162     /**
163      * Add new results to the compiled statistics. This could will generate a
164      * new &lt;result&gt; element and may be a new &lt;file&gt; element.
165      */
166     protected final void addNewResults() {
167         if (getFileStatistics() != 0) {
168             exporter.addFileResult(getFileStatistics(), currentFile);
169         } else {
170             if (!isQuiet()) {
171                 taskLogger.log("No violation for " + currentFile);
172             }
173         }
174     }
175 
176     /**
177      * @return give the total number of violations.
178      */
179     public int getTotalStatistics() {
180         return totalStatistics;
181     }
182 
183     /**
184      * @param increment
185      *            add increment to total number of violations.
186      */
187     protected final void addTotalStatistics(final int increment) {
188         totalStatistics += increment;
189     }
190 
191     /**
192      * Directly set the total statistics.
193      * 
194      * @param value
195      */
196     protected final void setTotalStatistics(final int value) {
197         totalStatistics = value;
198     }
199 
200     /**
201      * @return number of file counted.
202      */
203     public final int getFileCount() {
204         return fileCount;
205     }
206 
207     /**
208      * Increment file count by increment.
209      * 
210      * @param increment
211      *            increase file count by this value.
212      */
213     protected final void incrementFileCount(final int increment) {
214         fileCount += increment;
215     }
216 
217     /**
218      * @return number of violation for current file.
219      */
220     protected final int getFileStatistics() {
221         return fileStatistics;
222     }
223 
224     /**
225      * add a increment of file violation and also add it to the total violation
226      * count.
227      * 
228      * @param increment
229      *            value to add to the number of fileStatistics.
230      */
231     protected final void addFileStatistics(final int increment) {
232         fileStatistics += increment;
233         addTotalStatistics(increment);
234     }
235 
236     /**
237      * reset the fileStatistics to 0, typically when handling a new file.
238      */
239     protected final void resetFileStatistics() {
240         fileStatistics = 0;
241     }
242 
243     /**
244      * called by the ant task or the maven plug in.
245      * 
246      * @param source
247      *            the Reader from the statistics file.
248      * @param qalabExporter
249      *            the QALabExporter to use for saving the stats.
250      */
251     public final void mergeStats(final InputSource source,
252             final QALabExporter qalabExporter) {
253         exporter = qalabExporter;
254 
255         try {
256             final SAXParserFactory factory = SAXParserFactory.newInstance();
257             final SAXParser saxParser = factory.newSAXParser();
258 
259             saxParser.getXMLReader().setEntityResolver(new EntityResolver() {
260                 public InputSource resolveEntity(String publicId,
261                         String systemId) throws SAXException, IOException {
262                     
263                     return new InputSource();
264                 }
265             });
266             // As suggested by Nascif Abousalh-Neto, using an external DTD for
267             // this may
268             // cause some issues with Cobertura. See article for some features:
269             // http://www-128.ibm.com/developerworks/xml/library/x-tipcfsx.html
270             saxParser.getXMLReader().setFeature(
271                     "http://xml.org/sax/features/external-general-entities",
272                     false);
273             saxParser.getXMLReader().setFeature(
274                     "http://xml.org/sax/features/external-parameter-entities",
275                     false);
276 
277             InputSource src = preProcessSource(source);
278             
279             saxParser.parse(src, this);
280         } catch (ParserConfigurationException e) {
281             getTaskLogger().log(e.toString());
282         } catch (SAXException e) {
283             getTaskLogger().log(e.toString());
284         } catch (IOException e) {
285             e.printStackTrace();
286             getTaskLogger().log(e.toString());
287         } finally {
288             if (!isQuiet()) {
289                 getTaskLogger().log("Finished Parsing Source XML.");
290             }
291         }
292 
293         if (getTotalStatistics() != 0) {
294             exporter.addSummary(getTotalStatistics(), getFileCount());
295         }
296     }
297 
298     protected InputSource preProcessSource(InputSource source) {
299 //        return new InputSource(source);
300         return source;
301     }
302 
303     /**
304      * set the merger time stamp to use for all stats.
305      * 
306      * @param timestamp
307      *            the timestamp "YYYY-MM-dd HH:mm:ss"
308      * @param timeStampAsDate
309      *            The timeStampAsDateOnly to set.
310      */
311     public final void setMergerTimeStamp(final String timestamp,
312             final boolean timeStampAsDate) {
313         this.timeStampAsDateOnly = timeStampAsDate;
314         if (timestamp != null) {
315             try {
316                 mergerTimeStamp = QALabTags.DEFAULT_DATETIME_FORMAT
317                         .parse(timestamp);
318             } catch (ParseException e) {
319                 throw new IllegalArgumentException(
320                         "Wrong format for mergerTimeStamp. " + e.getMessage());
321             }
322         } else {
323             mergerTimeStamp = new Date();
324         }
325 
326         if (timeStampAsDate) {
327             Calendar cal = Calendar.getInstance();
328             cal.setTime(mergerTimeStamp);
329             cal.set(Calendar.HOUR_OF_DAY, 0);
330             cal.set(Calendar.MINUTE, 0);
331             cal.set(Calendar.SECOND, 0);
332             cal.set(Calendar.MILLISECOND, 0);
333             mergerTimeStamp = cal.getTime();
334         }
335     }
336 
337     /**
338      * This may have been changed to "now".
339      * 
340      * @return timestamp the time stamp in format YYYY-MM-dd HH:mm:ss
341      */
342     public final String getMergerTimeStamp() {
343         if (mergerTimeStamp == null) {
344             setMergerTimeStamp(null, timeStampAsDateOnly);
345         }
346 
347         if (timeStampAsDateOnly) {
348             return QALabTags.DEFAULT_DATE_FORMAT.format(mergerTimeStamp);
349         } else {
350             return QALabTags.DEFAULT_DATETIME_FORMAT.format(mergerTimeStamp);
351         }
352     }
353 }
354 /*
355  *                   ObjectLab is sponsoring QALab
356  * 
357  * Based in London, we are world leaders in the design and development 
358  * of bespoke applications for the securities financing markets.
359  * 
360  * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
361  *           ___  _     _           _   _          _
362  *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
363  *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
364  *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
365  *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
366  *                   |__/
367  *
368  *                     www.ObjectLab.co.uk
369  */