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 }