root/trunk/src/java/org/jcoderz/phoenix/report/ReportNormalizer.java

Revision 1468, 18.7 kB (checked in by amandel, 3 years ago)

Take care for tab characters - at least at the beginning of a line.

  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.phoenix.report;
34
35import java.io.File;
36import java.io.FileNotFoundException;
37import java.io.FileOutputStream;
38import java.io.IOException;
39import java.io.OutputStream;
40import java.util.ArrayList;
41import java.util.HashMap;
42import java.util.List;
43import java.util.Map;
44import java.util.logging.Level;
45import java.util.logging.Logger;
46
47import javax.xml.bind.JAXBException;
48import javax.xml.transform.Transformer;
49import javax.xml.transform.TransformerConfigurationException;
50import javax.xml.transform.TransformerException;
51import javax.xml.transform.TransformerFactory;
52import javax.xml.transform.TransformerFactoryConfigurationError;
53import javax.xml.transform.stream.StreamResult;
54import javax.xml.transform.stream.StreamSource;
55
56import org.jcoderz.commons.util.FileUtils;
57import org.jcoderz.commons.util.IoUtil;
58import org.jcoderz.commons.util.LoggingUtils;
59import org.jcoderz.phoenix.report.jaxb.Item;
60import org.jcoderz.phoenix.report.jaxb.ObjectFactory;
61
62/**
63 * Provides merging of findbugs, pmd, checkstyle, cpd, and cobertura
64 * XML files into a single XML representation.
65 *
66 * @author Michael Griffel
67 * @author Michael Rumpf
68 */
69public final class ReportNormalizer
70{
71
72    /** The Constant JCODERZ_REPORT_XML. */
73    public static final String JCODERZ_REPORT_XML
74        = "jcoderz-report.xml";
75
76    /** The Constant CLASSNAME. */
77    private static final String CLASSNAME
78        = ReportNormalizer.class.getName();
79
80    /** The Constant logger. */
81    private static final Logger logger
82        = Logger.getLogger(CLASSNAME);
83
84    /** The project home. */
85    private File mProjectHome;
86
87    /** The project name. */
88    private String mProjectName = "Unknown Project";
89
90    /** The out file. */
91    private File mOutFile;
92
93    /** The log level. */
94    private Level mLogLevel = Level.INFO;
95
96    /** The report level. */
97    private ReportLevel mLevel = ReportLevel.PROD;
98
99    /** The report list. */
100    private List<SourceReport> mReportList
101        = new ArrayList<SourceReport>();
102
103    /** The src list. */
104    private List<SourceReport> mSrcList
105        = new ArrayList<SourceReport>();
106
107    /**
108     * The XSL stylesheet that can be used to filter the
109     * jcoderz-report XML file.
110     */
111    private File mFilterFile = null;
112
113    /**
114     * Constructor.
115     *
116     * @throws IOException in case of any error.
117     */
118    public ReportNormalizer ()
119        throws IOException
120    {
121        mProjectHome = new File(".").getCanonicalFile();
122        mOutFile = new File(JCODERZ_REPORT_XML);
123    }
124
125    /**
126     * Main method.
127     *
128     * @param args arguments.
129     *
130     * @throws Exception the exception
131     */
132    public static void main (String[] args)
133        throws Exception
134    {
135        try
136        {
137            final ReportNormalizer rn = new ReportNormalizer();
138            rn.parseArguments(args);
139            rn.run();
140        }
141        catch (Exception e)
142        {
143            logger.log(Level.WARNING, "Failed in Normalizer.", e);
144            throw e;
145        }
146    }
147
148    /**
149     * Run ReportNormalizer.
150     */
151    public void run () throws JAXBException, IOException, TransformerException
152    {
153        logger.fine("Running report normalizer on #" + mReportList.size()
154            + " reports ...");
155        final Map<ResourceInfo, List<Item>> items
156            = new HashMap<ResourceInfo, List<Item>>();
157        for (SourceReport report : mSrcList)
158        {
159            handleReport(report, items);
160        }
161        for (SourceReport report : mReportList)
162        {
163            handleReport(report, items);
164        }
165
166        final JcoderzReport myReport = new JcoderzReport();
167        myReport.setProjectHome(mProjectHome.getAbsolutePath());
168        myReport.setProjectName(mProjectName);
169        myReport.setLevel(mLevel);
170
171        // XML report
172        final OutputStream out = new FileOutputStream(mOutFile);
173        try
174        {
175            myReport.write(out, items);
176        }
177        finally
178        {
179            IoUtil.close(out);
180        }
181
182        // apply filters to the report
183        if (mFilterFile != null)
184        {
185            filter();
186        }
187    }
188
189    /**
190     * Handle report.
191     *
192     * @param report the report
193     * @param items the items
194     *
195     * @throws JAXBException the JAXB exception
196     */
197    private void handleReport (SourceReport report,
198        final Map<ResourceInfo, List<Item>> items)
199            throws JAXBException
200    {
201        try
202        {
203            logger.fine("Processing report " + report.getReportFormat()
204                + " '" + report.getFilename() + "'");
205           
206           
207           
208            if (report.getFilename().length() != 0
209                || report.getFilename().isDirectory())
210            {
211                final ReportReader reportReader
212                    = ReportReaderFactory.createReader(report);
213                reportReader.parse(report.getFilename());
214                reportReader.merge(items);
215            }
216            else
217            {
218                logger.fine("Good job, no findings reported by "
219                    + report.getReportFormat());
220            }
221        }
222        catch (Exception e)
223        {
224            logger.log(Level.SEVERE, "Error while processing", e);
225            final Item item = new ObjectFactory().createItem();
226            item.setMessage("Error while Processing '"
227                + report.getReportFormat() + "' '"
228                + report.getFilename() + "' got Exception: '" + e + "'.");
229            item.setSeverity(Severity.ERROR);
230            item.setFindingType(SystemFindingType.SYS_PARSE_ERROR.getSymbol());
231            item.setOrigin(Origin.SYSTEM);
232            final ResourceInfo res
233                = ResourceInfo.register(report.getFilename().getAbsolutePath(),
234                    "", report.getFilename().getAbsolutePath());
235            if (items.containsKey(res))
236            {
237                items.get(res).add(item);
238            }
239            else
240            {
241                final List<Item> list = new ArrayList<Item>();
242                list.add(item);
243                items.put(res, list);
244            }
245        }
246    }
247
248    /**
249     * Filters the report XML file using the JDK XSL processor.
250     *
251     * @throws TransformerFactoryConfigurationError
252     *      the transformer factory configuration error
253     * @throws TransformerConfigurationException
254     *      the transformer configuration exception
255     * @throws IOException Signals that an I/O exception has occurred.
256     * @throws TransformerException the transformer exception
257     * @throws FileNotFoundException the file not found exception
258     */
259    private void filter ()
260        throws TransformerFactoryConfigurationError,
261            TransformerConfigurationException, IOException,
262            TransformerException, FileNotFoundException
263    {
264        logger.log(Level.FINE, "Filter: " + mFilterFile);
265        final TransformerFactory tFactory = TransformerFactory.newInstance();
266
267        final Transformer transformer = tFactory.newTransformer(
268            new StreamSource(mFilterFile));
269
270        final File tempOutputFile = new File(
271            mOutFile.getCanonicalPath() + ".tmp");
272        FileUtils.createNewFile(tempOutputFile);
273
274        final FileOutputStream out = new FileOutputStream(tempOutputFile);
275        try
276        {
277            transformer.transform(new StreamSource(mOutFile),
278                new StreamResult(out));
279        }
280        finally
281        {
282            IoUtil.close(out);
283        }
284        FileUtils.copyFile(tempOutputFile, mOutFile);
285        FileUtils.delete(tempOutputFile);
286    }
287
288    /**
289     * The following parameters select the different reports
290     * to combine into a single report.
291     *
292     * <ul>
293     * <li><code>-jcoverage jvoveragereport.xml</code> (http://???)</li>
294     * <li><code>-cobertura coberturareport.xml</code> (http://???)</li>
295     * <li><code>-checkstyle checkstylereport.xml</code>
296     * (http://checkstyle.sf.net)</li>
297     * <li><code>-findbugs findbugsreport.xml</code>
298     * (http://findbugs.sf.net)</li>
299     * <li><code>-pmd pmdreport.xml</code> (http://pmd.sf.net)</li>
300     * <li><code>-cpd cpdreport.xml</code> (http://))))</li>
301     * <li><code>-generic javadoc javadoc.log</code> (http://))))</li>
302     * </ul>
303     *
304     * <ul>
305     * <li><code>-projectHome</code></li>
306     * <li><code>-filter filter.xsl</code></li>
307     * <li><code>-srcDir</code></li>
308     * <li><code>-projectName</code></li>
309     * <li><code>-level PROD|TEST|MISC</code> The weight level</li>
310     * <li><code>-loglevel</code></li>
311     * <li><code>-out</code></li>
312     * </ul>
313     *
314     * @param args The command line arguments
315     *
316     * @return The list of reports to normalize
317     *
318     * @throws IOException When the filter file cannot be found
319     */
320    private void parseArguments (String[] args)
321        throws IOException
322    {
323        try
324        {
325            for (int i = 0; i < args.length; )
326            {
327                logger.fine("Parsing argument '" + args[i] + "' = '"
328                    + args[i + 1] + "'");
329
330                if (args[i].equals("-jcoverage"))
331                {
332                    addReport(ReportFormat.JCOVERAGE, args[i + 1]);
333                }
334                else if (args[i].equals("-cobertura"))
335                {
336                    addReport(ReportFormat.COBERTURA, args[i + 1]);
337                }
338                else if (args[i].equals("-checkstyle"))
339                {
340                    addReport(ReportFormat.CHECKSTYLE, args[i + 1]);
341                }
342                else if (args[i].equals("-findbugs"))
343                {
344                    addReport(ReportFormat.FINDBUGS, args[i + 1]);
345                }
346                else if (args[i].equals("-pmd"))
347                {
348                    addReport(ReportFormat.PMD, args[i + 1]);
349                }
350                else if (args[i].equals("-emma"))
351                {
352                    addReport(ReportFormat.EMMA, args[i + 1]);
353                }
354                else if (args[i].equals("-cpd"))
355                {
356                    addReport(ReportFormat.CPD, args[i + 1]);
357                }
358                else if (args[i].equals("-generic"))
359                {
360                    addReport(ReportFormat.GENERIC, args[++i], args[i + 1]);
361                }
362                else if (args[i].equals("-projectHome"))
363                {
364                    setProjectHome(new File(args[i + 1]));
365                }
366                else if (args[i].equals("-filter"))
367                {
368                    setFilterFile(new File(args[i + 1]));
369                }
370                else if (args[i].equals("-srcDir"))
371                {
372                    addReport(ReportFormat.SOURCE_DIRECTORY, args[i + 1]);
373                }
374                else if (args[i].equals("-projectName"))
375                {
376                    setProjectName(args[i + 1]);
377                }
378                else if (args[i].equals("-level"))
379                {
380                    setLevel(ReportLevel.fromString(args[i + 1]));
381                }
382                else if (args[i].equals("-loglevel"))
383                {
384                    setLogLevel(Level.parse(args[i + 1]));
385                }
386                else if (args[i].equals("-out"))
387                {
388                    setOutFile(new File(args[i + 1]));
389                }
390                else
391                {
392                    throw new IllegalArgumentException(
393                        "Invalid argument '" + args[i]  + "'");
394                }
395
396                ++i;
397                ++i;
398            }
399        }
400        catch (IndexOutOfBoundsException e)
401        {
402            final IllegalArgumentException ex = new IllegalArgumentException(
403                "Missing value for " + args[args.length - 1]);
404            ex.initCause(e);
405            throw ex;
406        }
407    }
408
409    /**
410     * Adds the report.
411     *
412     * @param format the format
413     * @param file the file
414     */
415    public void addReport (ReportFormat format, String file)
416    {
417        addReport(format, new File(file));
418    }
419   
420    /**
421     * Adds the report with a given flavor.
422     * The flavor is used for generic reports to detect the type of file.
423     *
424     * @param format the format
425     * @param file the file
426     * @param flavor the flavor of the report.
427     */
428    public void addReport (ReportFormat format, String file, String flavor)
429    {
430        mReportList.add(new SourceReport(format, new File(file), flavor));
431    }
432
433    /**
434     * Adds the report.
435     *
436     * @param format the format
437     * @param file the file
438     */
439    public void addReport (ReportFormat format, File file)
440    {
441        if (format == ReportFormat.SOURCE_DIRECTORY)
442        {
443            addSource(file);
444        }
445        else
446        {
447            mReportList.add(new SourceReport(format, file));
448        }
449    }
450
451
452    public void addSource (File srcDir)
453    {
454        mSrcList.add(new SourceReport(
455            ReportFormat.SOURCE_DIRECTORY, srcDir));
456    }
457
458    /**
459     * Gets the project home.
460     *
461     * @return the project home
462     */
463    public File getProjectHome ()
464    {
465        return mProjectHome;
466    }
467
468    /**
469     * Sets the project home.
470     *
471     * @param projectHome the new project home
472     */
473    public void setProjectHome (File projectHome)
474    {
475        mProjectHome = projectHome;
476    }
477
478    /**
479     * Gets the project name.
480     *
481     * @return the project name
482     */
483    public String getProjectName ()
484    {
485        return mProjectName;
486    }
487
488    /**
489     * Sets the project name.
490     *
491     * @param projectName the new project name
492     */
493    public void setProjectName (String projectName)
494    {
495        mProjectName = projectName;
496    }
497
498    /**
499     * Gets the out file.
500     *
501     * @return the out file
502     */
503    public File getOutFile ()
504    {
505        return mOutFile;
506    }
507
508    /**
509     * Sets the out file.
510     *
511     * @param outFile the new out file
512     *
513     * @throws IOException Signals that an I/O exception has occurred.
514     */
515    public void setOutFile (File outFile) throws IOException
516    {
517        if (outFile.isDirectory())
518        {
519            mOutFile
520            = new File(outFile, JCODERZ_REPORT_XML).getCanonicalFile();
521        }
522        else
523        {
524            mOutFile = outFile.getCanonicalFile();
525        }
526    }
527
528    /**
529     * Gets the log level.
530     *
531     * @return the log level
532     */
533    public Level getLogLevel ()
534    {
535        return mLogLevel;
536    }
537
538    /**
539     * Sets the log level.
540     *
541     * @param logLevel the new log level
542     */
543    public void setLogLevel (Level logLevel)
544    {
545        mLogLevel = logLevel;
546        LoggingUtils.setGlobalHandlerLogLevel(mLogLevel);
547        logger.config("Setting log level: " + mLogLevel);
548        Logger.getLogger("org.jcoderz.phoenix.report")
549            .setLevel(mLogLevel);
550    }
551
552    /**
553     * Gets the level.
554     *
555     * @return the level
556     */
557    public ReportLevel getLevel ()
558    {
559        return mLevel;
560    }
561
562    /**
563     * Sets the level.
564     *
565     * @param level the new level
566     */
567    public void setLevel (ReportLevel level)
568    {
569        mLevel = level;
570    }
571
572    /**
573     * Gets the filter file.
574     *
575     * @return the filter file
576     */
577    public File getFilterFile ()
578    {
579        return mFilterFile;
580    }
581
582    /**
583     * Sets the filter file.
584     *
585     * @param filterFile the new filter file
586     *
587     * @throws IOException Signals that an I/O exception has occurred.
588     */
589    public void setFilterFile (File filterFile)
590        throws IOException
591    {
592        mFilterFile = filterFile;
593        // Do not fail here if the argument is invalid.
594        if (!mFilterFile.exists())
595        {
596            throw new IOException("Filter file '" + mFilterFile
597                + "' does not exists.");
598        }
599    }
600
601    /**
602     * The Class SourceReport.
603     */
604    public static final class SourceReport
605    {
606
607        /** The report format. */
608        private final ReportFormat mReportFormat;
609
610        /** The filename. */
611        private final File mFilename;
612
613        /** The flavor. */
614        private final String mFlavor;
615       
616        /**
617         * Instantiates a new source report.
618         * No check here. Let the report parsing fail.
619         * @param r the ReportFormat
620         * @param f the File
621         */
622        SourceReport (ReportFormat r, File f)
623        {
624            mReportFormat = r;
625            mFilename = f;
626            mFlavor = null;
627        }
628
629        /**
630         * Instantiates a new source report.
631         * No check here. Let the report parsing fail.
632         * @param r the ReportFormat
633         * @param f the File
634         * @param flavor the report flavor
635         */
636        SourceReport (ReportFormat r, File f, String flavor)
637        {
638            mReportFormat = r;
639            mFilename = f;
640            mFlavor = flavor;
641        }
642
643        /**
644         * Returns the filename.
645         *
646         * @return the filename.
647         */
648        File getFilename ()
649        {
650            return mFilename;
651        }
652
653        /**
654         * Returns the reportFormat.
655         *
656         * @return the reportFormat.
657         */
658        ReportFormat getReportFormat ()
659        {
660            return mReportFormat;
661        }
662
663        /**
664         * Returns the report flavor.
665         *
666         * @return the report flavor.
667         */
668        public String getFlavor ()
669        {
670            return mFlavor;
671        }
672    }
673}
Note: See TracBrowser for help on using the browser.