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 */
023package com.jcoverage.coverage.reporting;
024
025import java.io.File;
026import java.io.IOException;
027import java.util.HashMap;
028import java.util.Iterator;
029import java.util.Map;
030
031import org.apache.log4j.Logger;
032
033import com.jcoverage.coverage.Instrumentation;
034import com.jcoverage.coverage.reporting.collation.JavaFileLine;
035import com.jcoverage.coverage.reporting.collation.JavaFilePage;
036import com.jcoverage.coverage.reporting.collation.PackageSummaryPage;
037import com.jcoverage.coverage.reporting.collation.ReportImpl;
038import com.jcoverage.coverage.reporting.collation.ReportSummaryPackageLine;
039import com.jcoverage.coverage.reporting.collation.ReportSummaryPage;
040import com.jcoverage.coverage.reporting.collation.StaticFileCollator;
041import com.jcoverage.coverage.reporting.html.MultiViewStaticHtmlFormat;
042import com.jcoverage.reporting.Collator;
043import com.jcoverage.reporting.FileSerializer;
044import com.jcoverage.reporting.Format;
045import com.jcoverage.reporting.Line;
046import com.jcoverage.reporting.Page;
047import com.jcoverage.reporting.Report;
048import com.jcoverage.reporting.Serializer;
049import 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 */
055public 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}