Home | History | Annotate | Download | only in report
      1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
      2  *
      3  * This program and the accompanying materials are made available under
      4  * the terms of the Common Public License v1.0 which accompanies this distribution,
      5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
      6  *
      7  * $Id: ReportProcessor.java,v 1.1.1.1.2.2 2004/07/16 23:32:29 vlad_r Exp $
      8  */
      9 package com.vladium.emma.report;
     10 
     11 import java.io.File;
     12 import java.io.IOException;
     13 
     14 import com.vladium.logging.Logger;
     15 import com.vladium.util.Files;
     16 import com.vladium.util.IConstants;
     17 import com.vladium.util.IProperties;
     18 import com.vladium.util.Strings;
     19 import com.vladium.util.asserts.$assert;
     20 import com.vladium.util.exception.Exceptions;
     21 import com.vladium.emma.IAppConstants;
     22 import com.vladium.emma.IAppErrorCodes;
     23 import com.vladium.emma.EMMARuntimeException;
     24 import com.vladium.emma.Processor;
     25 import com.vladium.emma.data.DataFactory;
     26 import com.vladium.emma.data.ICoverageData;
     27 import com.vladium.emma.data.IMergeable;
     28 import com.vladium.emma.data.IMetaData;
     29 
     30 // ----------------------------------------------------------------------------
     31 /*
     32  * This class was not meant to be public by design. It is made to to work around
     33  * access bugs in reflective invocations.
     34  */
     35 /**
     36  * @author Vlad Roubtsov, (C) 2003
     37  */
     38 public
     39 final class ReportProcessor extends Processor
     40                             implements IAppErrorCodes
     41 {
     42     // public: ................................................................
     43 
     44     public static ReportProcessor create ()
     45     {
     46         return new ReportProcessor ();
     47     }
     48 
     49     /**
     50      *
     51      * @param path [null is equivalent to an empty array]
     52      */
     53     public synchronized final void setDataPath (final String [] path)
     54     {
     55         if ((path == null) || (path.length == 0))
     56             m_dataPath = IConstants.EMPTY_FILE_ARRAY;
     57         else
     58             m_dataPath = Files.pathToFiles (path, true);
     59     }
     60 
     61     /**
     62      * @param path [null is equivalent to no source path]
     63      */
     64     public synchronized void setSourcePath (final String [] path)
     65     {
     66         if (path == null)
     67             m_sourcePath = null;
     68         else
     69             m_sourcePath = Files.pathToFiles (path, true); // always canonicalize source path
     70     }
     71 
     72     /**
     73      *
     74      * @param types [may not be null]
     75      */
     76     public synchronized void setReportTypes (final String [] types)
     77     {
     78         if (types == null) throw new IllegalArgumentException ("null input: types");
     79 
     80         final String [] reportTypes = Strings.removeDuplicates (types, true);
     81         if (reportTypes.length == 0) throw new IllegalArgumentException ("empty input: types");
     82 
     83         if ($assert.ENABLED) $assert.ASSERT (reportTypes != null && reportTypes.length  > 0);
     84 
     85 
     86         final IReportGenerator [] reportGenerators = new IReportGenerator [reportTypes.length];
     87         for (int t = 0; t < reportTypes.length; ++ t)
     88         {
     89             reportGenerators [t] = AbstractReportGenerator.create (reportTypes [t]);
     90         }
     91 
     92         m_reportGenerators = reportGenerators;
     93     }
     94 
     95     // protected: .............................................................
     96 
     97 
     98     protected void validateState ()
     99     {
    100         super.validateState ();
    101 
    102         if (m_dataPath == null)
    103             throw new IllegalStateException ("data path not set");
    104 
    105         // [m_sourcePath can be null]
    106 
    107         if ((m_reportGenerators == null) || (m_reportGenerators.length == 0))
    108             throw new IllegalStateException ("report types not set");
    109 
    110         // [m_propertyOverrides can be null]
    111     }
    112 
    113 
    114     protected void _run (final IProperties toolProperties)
    115     {
    116         final Logger log = m_log;
    117 
    118         final boolean verbose = m_log.atVERBOSE ();
    119         if (verbose)
    120         {
    121             log.verbose (IAppConstants.APP_VERBOSE_BUILD_ID);
    122 
    123             // [assertion: m_dataPath != null]
    124             log.verbose ("input data path:");
    125             log.verbose ("{");
    126             for (int p = 0; p < m_dataPath.length; ++ p)
    127             {
    128                 final File f = m_dataPath [p];
    129                 final String nonexistent = f.exists () ? "" : "{nonexistent} ";
    130 
    131                 log.verbose ("  " + nonexistent + f.getAbsolutePath ());
    132             }
    133             log.verbose ("}");
    134 
    135 
    136             if ((m_sourcePath == null) || (m_sourcePath.length == 0))
    137             {
    138                 log.verbose ("source path not set");
    139             }
    140             else
    141             {
    142                 log.verbose ("source path:");
    143                 log.verbose ("{");
    144                 for (int p = 0; p < m_sourcePath.length; ++ p)
    145                 {
    146                     final File f = m_sourcePath [p];
    147                     final String nonexistent = f.exists () ? "" : "{nonexistent} ";
    148 
    149                     log.verbose ("  " + nonexistent + f.getAbsolutePath ());
    150                 }
    151                 log.verbose ("}");
    152             }
    153         }
    154         else
    155         {
    156             log.info ("processing input files ...");
    157         }
    158 
    159         RuntimeException failure = null;
    160         try
    161         {
    162             final long start = log.atINFO () ? System.currentTimeMillis () : 0;
    163 
    164             IMetaData mdata = null;
    165             ICoverageData cdata = null;
    166 
    167             // merge all data files:
    168             try
    169             {
    170                 for (int f = 0; f < m_dataPath.length; ++ f)
    171                 {
    172                     final File dataFile = m_dataPath [f];
    173                     if (verbose) log.verbose ("processing input file [" + dataFile.getAbsolutePath () + "] ...");
    174 
    175                     final IMergeable [] fileData = DataFactory.load (dataFile);
    176 
    177                     final IMetaData _mdata = (IMetaData) fileData [DataFactory.TYPE_METADATA];
    178                     if (_mdata != null)
    179                     {
    180                         if (verbose) log.verbose ("  loaded " + _mdata.size () + " metadata entries");
    181 
    182                         if (mdata == null)
    183                             mdata = _mdata;
    184                         else
    185                             mdata = (IMetaData) mdata.merge (_mdata); // note: later datapath entries override earlier ones
    186                     }
    187 
    188                     final ICoverageData _cdata = (ICoverageData) fileData [DataFactory.TYPE_COVERAGEDATA];
    189                     if (_cdata != null)
    190                     {
    191                         if (verbose) log.verbose ("  loaded " + _cdata.size () + " coverage data entries");
    192 
    193                         if (cdata == null)
    194                             cdata = _cdata;
    195                         else
    196                             cdata = (ICoverageData) cdata.merge (_cdata); // note: later datapath entries override earlier ones
    197                     }
    198 
    199                     ++ m_dataFileCount;
    200                 }
    201 
    202                 if (log.atINFO ())
    203                 {
    204                     final long end = System.currentTimeMillis ();
    205 
    206                     log.info (m_dataFileCount + " file(s) read and merged in " + (end - start) + " ms");
    207                 }
    208 
    209                 if ((mdata == null) || mdata.isEmpty ())
    210                 {
    211                     log.warning ("nothing to do: no metadata found in any of the data files");
    212 
    213                     return;
    214                 }
    215 
    216                 if (cdata == null)
    217                 {
    218                     log.warning ("nothing to do: no runtime coverage data found in any of the data files");
    219 
    220                     return;
    221                 }
    222 
    223                 if (cdata.isEmpty ())
    224                 {
    225                     log.warning ("no collected coverage data found in any of the data files [all reports will be empty]");
    226                 }
    227 
    228 
    229                 if (verbose)
    230                 {
    231                     if (mdata != null)
    232                     {
    233                         log.verbose ("  merged metadata contains " + mdata.size () + " entries");
    234                     }
    235 
    236                     if (cdata != null)
    237                     {
    238                         log.verbose ("  merged coverage data contains " + cdata.size () + " entries");
    239                     }
    240                 }
    241 
    242                 SourcePathCache srcpathCache = null;
    243                 if (m_sourcePath != null) srcpathCache = new SourcePathCache (m_sourcePath, true); // ignore non-existent source dirs
    244 
    245                 for (int g = 0; g < m_reportGenerators.length; ++ g)
    246                 {
    247                     final IReportGenerator generator = m_reportGenerators [g];
    248 
    249                     try
    250                     {
    251                         // no shallow copies of 'mdata' or 'cdata' are needed here
    252                         // because this command never runs in a concurrent situation
    253 
    254                         generator.process (mdata, cdata, srcpathCache, toolProperties);
    255                     }
    256                     catch (Throwable t)
    257                     {
    258                         // TODO: handle and continue
    259                         t.printStackTrace (System.out);
    260 
    261                         // TODO: continue here
    262                         break;
    263                     }
    264                     finally
    265                     {
    266                         try { generator.cleanup (); } catch (Throwable ignore) {}
    267                     }
    268                 }
    269             }
    270             catch (IOException ioe)
    271             {
    272                 // TODO: handle
    273                 ioe.printStackTrace (System.out);
    274             }
    275         }
    276         catch (SecurityException se)
    277         {
    278             failure = new EMMARuntimeException (SECURITY_RESTRICTION, new String [] {IAppConstants.APP_NAME}, se);
    279         }
    280         catch (RuntimeException re)
    281         {
    282             failure = re;
    283         }
    284         finally
    285         {
    286             reset ();
    287         }
    288 
    289         if (failure != null)
    290         {
    291             if (Exceptions.unexpectedFailure (failure, EXPECTED_FAILURES))
    292             {
    293                 throw new EMMARuntimeException (UNEXPECTED_FAILURE,
    294                                                 new Object [] {failure.toString (), IAppConstants.APP_BUG_REPORT_LINK},
    295                                                 failure);
    296             }
    297             else
    298                 throw failure;
    299         }
    300     }
    301 
    302     // package: ...............................................................
    303 
    304     // private: ...............................................................
    305 
    306 
    307     private ReportProcessor ()
    308     {
    309         m_dataPath = IConstants.EMPTY_FILE_ARRAY;
    310     }
    311 
    312     private void reset ()
    313     {
    314         m_dataFileCount = 0;
    315     }
    316 
    317 
    318     // caller-settable state [scoped to this runner instance]:
    319 
    320     private File [] m_dataPath;     // required to be non-null for run()
    321     private File [] m_sourcePath;   // can be null/empty for run()
    322     private IReportGenerator [] m_reportGenerators; // required to be non-null for run()
    323 
    324     // internal run()-scoped state:
    325 
    326     private int m_dataFileCount;
    327 
    328     private static final Class [] EXPECTED_FAILURES; // set in <clinit>
    329 
    330     static
    331     {
    332         EXPECTED_FAILURES = new Class []
    333         {
    334             EMMARuntimeException.class,
    335             IllegalArgumentException.class,
    336             IllegalStateException.class,
    337         };
    338     }
    339 
    340 } // end of class
    341 // ----------------------------------------------------------------------------