001    /**
002     * www.jcoverage.com
003     * Copyright (C)2003 jcoverage ltd.
004     *
005     * This file is part of jcoverage.
006     *
007     * jcoverage is free software; you can redistribute it and/or modify
008     * it under the terms of the GNU General Public License as published
009     * by the Free Software Foundation; either version 2 of the License,
010     * or (at your option) any later version.
011     *
012     * jcoverage is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * along with jcoverage; if not, write to the Free Software
019     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020     * USA
021     *
022     */
023    package com.jcoverage.coverage.reporting;
024    
025    import java.io.File;
026    import java.io.IOException;
027    import java.util.HashMap;
028    import java.util.Iterator;
029    import java.util.Map;
030    
031    import org.apache.log4j.Logger;
032    
033    import com.jcoverage.coverage.Instrumentation;
034    import com.jcoverage.coverage.reporting.collation.JavaFileLine;
035    import com.jcoverage.coverage.reporting.collation.JavaFilePage;
036    import com.jcoverage.coverage.reporting.collation.PackageSummaryPage;
037    import com.jcoverage.coverage.reporting.collation.ReportImpl;
038    import com.jcoverage.coverage.reporting.collation.ReportSummaryPackageLine;
039    import com.jcoverage.coverage.reporting.collation.ReportSummaryPage;
040    import com.jcoverage.coverage.reporting.collation.StaticFileCollator;
041    import com.jcoverage.coverage.reporting.html.MultiViewStaticHtmlFormat;
042    import com.jcoverage.reporting.Collator;
043    import com.jcoverage.reporting.FileSerializer;
044    import com.jcoverage.reporting.Format;
045    import com.jcoverage.reporting.Line;
046    import com.jcoverage.reporting.Page;
047    import com.jcoverage.reporting.Report;
048    import com.jcoverage.reporting.Serializer;
049    import com.jcoverage.util.ClassHelper;
050    
051    /**
052     * This class take Instrumentation instances and uses them to drive
053     * the generation of a report using the <a href="{@docRoot}/com/jcoverage/coverage/reporting/package-summary.html">report framework</a>.
054     */
055    public class ReportDriver {
056      static final Logger logger=Logger.getLogger(ReportDriver.class);
057    
058      File javaSourceDirectory;
059    
060      Report report=new ReportImpl();
061      Page indexPage;
062    
063      public ReportDriver(File javaSourceDirectory) {
064        this.javaSourceDirectory=javaSourceDirectory;
065        indexPage=report.createFrontPage();
066      }
067    
068      public synchronized void addInstrumentation(String clzName,Instrumentation instrumentation) {
069        if(logger.isDebugEnabled()) {
070          logger.debug("clzName: "+clzName);
071        }
072    
073        if(!isInnerClass(clzName)) {
074          String id=getSourceFileId(clzName,instrumentation);
075    
076          String sourcePath=id.replace('.','/')+".java";
077    
078    
079          String packageName=ClassHelper.getPackageName(id);
080          if (packageName.equals("")) {
081            packageName="default";
082          }
083          
084          // Need to add a package line for this
085          Line packageLine=indexPage.lookupLineByField(ReportSummaryPage.CATEGORY_PACKAGE_SUMMARY,ReportSummaryPackageLine.COLUMN_PACKAGE_NAME,packageName);
086          Page packageDetailPage=null;
087          if(packageLine==null) {
088            if(logger.isDebugEnabled()) {
089              logger.debug("Creating new line for packagename "+packageName);
090            }
091    
092            packageLine=indexPage.createLine(ReportSummaryPage.CATEGORY_PACKAGE_SUMMARY);
093            packageLine.setField(ReportSummaryPackageLine.COLUMN_PACKAGE_NAME,packageName);
094            packageDetailPage=packageLine.openDetailPage();
095          } else {
096            if(logger.isDebugEnabled()) {
097              logger.debug("Found existing line for packagename "+packageName);
098            }
099    
100            packageDetailPage=packageLine.getDetailPage();
101          }
102    
103          // Now add the class line
104          Line javaFileLine=packageDetailPage.lookupLineByField(PackageSummaryPage.CATEGORY_JAVAFILES,JavaFileLine.COLUMN_FILE_NAME,clzName);
105          Page javaFileDetailPage=null;
106          if (javaFileLine==null) {
107            if(logger.isDebugEnabled()) {
108              logger.debug("Creating new line for class "+clzName);
109            }
110    
111            javaFileLine=packageDetailPage.createLine(PackageSummaryPage.CATEGORY_JAVAFILES);
112            javaFileLine.setField(JavaFileLine.COLUMN_FILE_NAME,clzName);
113            javaFileLine.setField(JavaFileLine.COLUMN_PATH,new File(javaSourceDirectory,sourcePath).getAbsolutePath());
114            javaFileDetailPage=javaFileLine.openDetailPage();
115          } else {
116            if(logger.isDebugEnabled()) {
117              logger.debug("Found existing line for class "+clzName);
118            }
119    
120            javaFileDetailPage=javaFileLine.getDetailPage();
121          }
122    
123          // Add class line to summary
124          indexPage.addLineReference(javaFileLine,PackageSummaryPage.CATEGORY_JAVAFILES);
125          ((JavaFilePage)javaFileDetailPage).addInstrumentation(instrumentation);
126        }
127      }
128    
129      public void generate(File outputDir) throws Exception {
130        Collator collator=new StaticFileCollator(".html");
131        report.setCollator(collator);
132        Format htmlFormat=new MultiViewStaticHtmlFormat();
133        Serializer serializer=new FileSerializer(outputDir);
134        collator.addOutputter(htmlFormat,serializer);
135        indexPage.close();
136      }
137    
138      public static String getSourceFileId(String clzName,Instrumentation instrumentation) {
139        if(logger.isDebugEnabled()) {
140          logger.debug("clzName: "+clzName);
141        }
142    
143        if (isInnerClass(clzName)) {
144          throw new IllegalStateException("Cannot call this method (getSourceFileId) for an inner class");
145        }
146        String pkgname=ClassHelper.getPackageName(clzName);
147        
148        if(logger.isDebugEnabled()) {
149          logger.debug("pkgname: "+pkgname);
150        }
151    
152        if(instrumentation.getSourceFileName()==null) {
153          logger.fatal("Incomplete jcoverage.ser instrumentation. Do you need to merge?");
154          return clzName;
155        }
156    
157        if (pkgname.equals("")) {
158          return stripJavaSuffix(instrumentation.getSourceFileName());
159        } else {
160          return pkgname+"."+stripJavaSuffix(instrumentation.getSourceFileName());
161        }
162      }
163    
164      public static String stripJavaSuffix(String s) {
165        if(logger.isDebugEnabled()) {
166          logger.debug("s: "+s);
167        }
168        return s.substring(0,s.length()-".java".length());
169      }
170    
171      public static boolean isInnerClass(String clzName) {
172        return clzName.indexOf("$")!=-1;
173      }
174    }