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 }