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: AbstractReportGenerator.java,v 1.1.1.1.2.4 2005/04/24 23:51:37 vlad_r Exp $ 8 */ 9package com.vladium.emma.report; 10 11import java.util.Iterator; 12import java.util.Set; 13import java.util.TreeSet; 14 15import com.vladium.logging.Logger; 16import com.vladium.util.Descriptors; 17import com.vladium.util.IProperties; 18import com.vladium.util.IntIntMap; 19import com.vladium.util.IntVector; 20import com.vladium.util.ObjectIntMap; 21import com.vladium.emma.EMMARuntimeException; 22import com.vladium.emma.data.ClassDescriptor; 23import com.vladium.emma.data.ICoverageData; 24import com.vladium.emma.data.IMetaData; 25 26// ---------------------------------------------------------------------------- 27/** 28 * @author Vlad Roubtsov, (C) 2003 29 */ 30public 31abstract class AbstractReportGenerator extends AbstractItemVisitor 32 implements IReportGenerator 33{ 34 // public: ................................................................ 35 36 37 public static IReportGenerator create (final String type) 38 { 39 if ((type == null) || (type.length () == 0)) 40 throw new IllegalArgumentException ("null/empty input: type"); 41 42 // TODO: proper pluggability pattern here 43 44 if ("html".equals (type)) 45 return new com.vladium.emma.report.html.ReportGenerator (); 46 else if ("lcov".equals (type)) 47 return new com.vladium.emma.report.lcov.ReportGenerator (); 48 else if ("txt".equals (type)) 49 return new com.vladium.emma.report.txt.ReportGenerator (); 50 else if ("xml".equals (type)) 51 return new com.vladium.emma.report.xml.ReportGenerator (); 52 else // TODO: error code 53 throw new EMMARuntimeException ("no report generator class found for type [" + type + "]"); 54 } 55 56 57 public void initialize (final IMetaData mdata, final ICoverageData cdata, 58 final SourcePathCache cache, final IProperties properties) 59 throws EMMARuntimeException 60 { 61 m_log = Logger.getLogger (); 62 m_verbose = m_log.atVERBOSE (); 63 64 m_settings = ReportProperties.parseProperties (properties, getType ()); 65 66 m_cache = cache; 67 68 m_hasSrcFileInfo = mdata.hasSrcFileData (); 69 m_hasLineNumberInfo = mdata.hasLineNumberData (); 70 71 boolean debugInfoWarning = false; 72 boolean bailOut = false; 73 74 // src view is not possible if 'm_hasSrcFileInfo' is false: 75 if (! mdata.hasSrcFileData () && (m_settings.getViewType () == IReportDataView.HIER_SRC_VIEW)) 76 { 77 debugInfoWarning = true; 78 79 m_log.warning ("not all instrumented classes were compiled with source file"); 80 m_log.warning ("debug data: no sources will be embedded in the report."); 81 82 m_settings.setViewType (IReportDataView.HIER_CLS_VIEW); 83 } 84 85 // line coverage column must be removed if 'm_hasLineNumberInfo' is false: 86 if (! m_hasLineNumberInfo) 87 { 88 final int [] userColumnIDs = m_settings.getColumnOrder (); 89 final IntVector columnIDs = new IntVector (); 90 91 boolean removed = false; 92 for (int c = 0; c < userColumnIDs.length; ++ c) 93 { 94 if (userColumnIDs [c] == IItemAttribute.ATTRIBUTE_LINE_COVERAGE_ID) 95 removed = true; 96 else 97 columnIDs.add (userColumnIDs [c]); 98 } 99 100 // at this point it is possible that there are no columns left: bail out 101 if (removed) 102 { 103 debugInfoWarning = true; 104 105 if (columnIDs.size () == 0) 106 { 107 m_log.warning ("line coverage requested in a report of type [" + getType () + "] but"); 108 m_log.warning ("not all instrumented classes were compiled with line number"); 109 m_log.warning ("debug data: since this was the only requested column, no report will be generated."); 110 111 bailOut = true; 112 } 113 else 114 { 115 m_log.warning ("line coverage requested in a report of type [" + getType () + "] but"); 116 m_log.warning ("not all instrumented classes were compiled with line number"); 117 m_log.warning ("debug data: this column will be removed from the report."); 118 119 m_settings.setColumnOrder (columnIDs.values ()); 120 121 final int [] userSort = m_settings.getSortOrder (); 122 final IntVector sort = new IntVector (); 123 124 for (int c = 0; c < userSort.length; c += 2) 125 { 126 if (Math.abs (userSort [c]) != IItemAttribute.ATTRIBUTE_LINE_COVERAGE_ID) 127 { 128 sort.add (userSort [c]); 129 sort.add (userSort [c + 1]); 130 } 131 } 132 133 m_settings.setSortOrder (sort.values ()); 134 } 135 } 136 } 137 // note: no need to adjust m_metrics due to possible column removal above 138 139 // SF FR 971176: provide user with sample classes that caused the above warnings 140 if (debugInfoWarning && m_log.atINFO ()) 141 { 142 final Set /* String */ sampleClassNames = new TreeSet (); 143 final ObjectIntMap /* packageVMName:String -> count:int */ countMap = new ObjectIntMap (); 144 final int [] _count = new int [1]; 145 146 for (Iterator /* ClassDescriptor */ descriptors = mdata.iterator (); descriptors.hasNext (); ) 147 { 148 final ClassDescriptor cls = (ClassDescriptor) descriptors.next (); 149 150 // SF BUG 979717: this check was incorrectly absent in the initial FR impl: 151 if (! cls.hasCompleteLineNumberInfo () || ! cls.hasSrcFileInfo ()) 152 { 153 final String packageVMName = cls.getPackageVMName (); 154 final int count = countMap.get (packageVMName, _count) 155 ? _count [0] 156 : 0; 157 158 if (count < MAX_DEBUG_INFO_WARNING_COUNT) 159 { 160 sampleClassNames.add (Descriptors.vmNameToJavaName (cls.getClassVMName ())); 161 countMap.put (packageVMName, count + 1); 162 } 163 } 164 } 165 166 m_log.info ("showing up to " + MAX_DEBUG_INFO_WARNING_COUNT + " classes without full debug info per package:"); 167 for (Iterator /* String */ names = sampleClassNames.iterator (); names.hasNext (); ) 168 { 169 m_log.info (" " + names.next ()); 170 } 171 } 172 173 if (bailOut) 174 { 175 // TODO: error code 176 throw new EMMARuntimeException ("BAILED OUT"); 177 } 178 179 final IItemMetadata [] allTypes = IItemMetadata.Factory.getAllTypes (); 180 m_typeSortComparators = new ItemComparator [allTypes.length]; 181 182 for (int t = 0; t < allTypes.length; ++ t) 183 { 184 final IntVector orderedAttrIDsWithDir = new IntVector (); 185 final long typeAttrIDSet = allTypes [t].getAttributeIDs (); 186 187 for (int s = 0; s < m_settings.getSortOrder ().length; s += 2) 188 { 189 final int attrID = m_settings.getSortOrder () [s]; 190 191 if ((typeAttrIDSet & (1 << attrID)) != 0) 192 { 193 orderedAttrIDsWithDir.add (attrID); 194 195 final int dir = m_settings.getSortOrder () [s + 1]; 196 orderedAttrIDsWithDir.add (dir); 197 } 198 } 199 200 m_typeSortComparators [t] = ItemComparator.Factory.create (orderedAttrIDsWithDir.values (), m_settings.getUnitsType ()); 201 } 202 203 m_metrics = new int [allTypes.length]; 204 final IntIntMap metrics = m_settings.getMetrics (); 205 for (int t = 0; t < m_metrics.length; ++ t) 206 { 207 m_metrics [t] = -1; 208 metrics.get (t, m_metrics, t); 209 } 210 211 final IReportDataModel model = IReportDataModel.Factory.create (mdata, cdata); 212 m_view = model.getView (m_settings.getViewType ()); 213 214 m_srcView = (m_settings.getViewType () == IReportDataView.HIER_SRC_VIEW); 215 } 216 217 public void cleanup () 218 { 219 reset (); 220 } 221 222 // protected: ............................................................. 223 224 225 protected void reset () 226 { 227 m_settings = null; 228 m_cache = null; 229 m_view = null; 230 m_srcView = false; 231 232 //m_typeSortIDs = null; 233 m_typeSortComparators = null; 234 m_metrics = null; 235 236 m_log = null; 237 } 238 239 240 protected ReportProperties.ParsedProperties m_settings; 241 protected SourcePathCache m_cache; 242 protected IReportDataView m_view; 243 protected boolean m_srcView; 244 245 protected boolean m_hasSrcFileInfo, m_hasLineNumberInfo; 246 protected ItemComparator [] m_typeSortComparators; // m_typeSortComparators [t] is a comparator representing the sort order for item type t 247 protected int [] m_metrics; // -1 means no pass/fail check for this attribute 248 249 protected Logger m_log; // every report generator is used on a single thread but the logger needs to be run()-scoped 250 protected boolean m_verbose; 251 252 // package: ............................................................... 253 254 // private: ............................................................... 255 256 257 private static final int MAX_DEBUG_INFO_WARNING_COUNT = 3; // per package 258 259} // end of class 260// ---------------------------------------------------------------------------- 261