| /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under |
| * the terms of the Common Public License v1.0 which accompanies this distribution, |
| * and is available at http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * $Id: AbstractReportGenerator.java,v 1.1.1.1.2.4 2005/04/24 23:51:37 vlad_r Exp $ |
| */ |
| package com.vladium.emma.report; |
| |
| import java.util.Iterator; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import com.vladium.logging.Logger; |
| import com.vladium.util.Descriptors; |
| import com.vladium.util.IProperties; |
| import com.vladium.util.IntIntMap; |
| import com.vladium.util.IntVector; |
| import com.vladium.util.ObjectIntMap; |
| import com.vladium.emma.EMMARuntimeException; |
| import com.vladium.emma.data.ClassDescriptor; |
| import com.vladium.emma.data.ICoverageData; |
| import com.vladium.emma.data.IMetaData; |
| |
| // ---------------------------------------------------------------------------- |
| /** |
| * @author Vlad Roubtsov, (C) 2003 |
| */ |
| public |
| abstract class AbstractReportGenerator extends AbstractItemVisitor |
| implements IReportGenerator |
| { |
| // public: ................................................................ |
| |
| |
| public static IReportGenerator create (final String type) |
| { |
| if ((type == null) || (type.length () == 0)) |
| throw new IllegalArgumentException ("null/empty input: type"); |
| |
| // TODO: proper pluggability pattern here |
| |
| if ("html".equals (type)) |
| return new com.vladium.emma.report.html.ReportGenerator (); |
| else if ("txt".equals (type)) |
| return new com.vladium.emma.report.txt.ReportGenerator (); |
| else if ("xml".equals (type)) |
| return new com.vladium.emma.report.xml.ReportGenerator (); |
| else // TODO: error code |
| throw new EMMARuntimeException ("no report generator class found for type [" + type + "]"); |
| } |
| |
| |
| public void initialize (final IMetaData mdata, final ICoverageData cdata, |
| final SourcePathCache cache, final IProperties properties) |
| throws EMMARuntimeException |
| { |
| m_log = Logger.getLogger (); |
| m_verbose = m_log.atVERBOSE (); |
| |
| m_settings = ReportProperties.parseProperties (properties, getType ()); |
| |
| m_cache = cache; |
| |
| m_hasSrcFileInfo = mdata.hasSrcFileData (); |
| m_hasLineNumberInfo = mdata.hasLineNumberData (); |
| |
| boolean debugInfoWarning = false; |
| boolean bailOut = false; |
| |
| // src view is not possible if 'm_hasSrcFileInfo' is false: |
| if (! mdata.hasSrcFileData () && (m_settings.getViewType () == IReportDataView.HIER_SRC_VIEW)) |
| { |
| debugInfoWarning = true; |
| |
| m_log.warning ("not all instrumented classes were compiled with source file"); |
| m_log.warning ("debug data: no sources will be embedded in the report."); |
| |
| m_settings.setViewType (IReportDataView.HIER_CLS_VIEW); |
| } |
| |
| // line coverage column must be removed if 'm_hasLineNumberInfo' is false: |
| if (! m_hasLineNumberInfo) |
| { |
| final int [] userColumnIDs = m_settings.getColumnOrder (); |
| final IntVector columnIDs = new IntVector (); |
| |
| boolean removed = false; |
| for (int c = 0; c < userColumnIDs.length; ++ c) |
| { |
| if (userColumnIDs [c] == IItemAttribute.ATTRIBUTE_LINE_COVERAGE_ID) |
| removed = true; |
| else |
| columnIDs.add (userColumnIDs [c]); |
| } |
| |
| // at this point it is possible that there are no columns left: bail out |
| if (removed) |
| { |
| debugInfoWarning = true; |
| |
| if (columnIDs.size () == 0) |
| { |
| m_log.warning ("line coverage requested in a report of type [" + getType () + "] but"); |
| m_log.warning ("not all instrumented classes were compiled with line number"); |
| m_log.warning ("debug data: since this was the only requested column, no report will be generated."); |
| |
| bailOut = true; |
| } |
| else |
| { |
| m_log.warning ("line coverage requested in a report of type [" + getType () + "] but"); |
| m_log.warning ("not all instrumented classes were compiled with line number"); |
| m_log.warning ("debug data: this column will be removed from the report."); |
| |
| m_settings.setColumnOrder (columnIDs.values ()); |
| |
| final int [] userSort = m_settings.getSortOrder (); |
| final IntVector sort = new IntVector (); |
| |
| for (int c = 0; c < userSort.length; c += 2) |
| { |
| if (Math.abs (userSort [c]) != IItemAttribute.ATTRIBUTE_LINE_COVERAGE_ID) |
| { |
| sort.add (userSort [c]); |
| sort.add (userSort [c + 1]); |
| } |
| } |
| |
| m_settings.setSortOrder (sort.values ()); |
| } |
| } |
| } |
| // note: no need to adjust m_metrics due to possible column removal above |
| |
| // SF FR 971176: provide user with sample classes that caused the above warnings |
| if (debugInfoWarning && m_log.atINFO ()) |
| { |
| final Set /* String */ sampleClassNames = new TreeSet (); |
| final ObjectIntMap /* packageVMName:String -> count:int */ countMap = new ObjectIntMap (); |
| final int [] _count = new int [1]; |
| |
| for (Iterator /* ClassDescriptor */ descriptors = mdata.iterator (); descriptors.hasNext (); ) |
| { |
| final ClassDescriptor cls = (ClassDescriptor) descriptors.next (); |
| |
| // SF BUG 979717: this check was incorrectly absent in the initial FR impl: |
| if (! cls.hasCompleteLineNumberInfo () || ! cls.hasSrcFileInfo ()) |
| { |
| final String packageVMName = cls.getPackageVMName (); |
| final int count = countMap.get (packageVMName, _count) |
| ? _count [0] |
| : 0; |
| |
| if (count < MAX_DEBUG_INFO_WARNING_COUNT) |
| { |
| sampleClassNames.add (Descriptors.vmNameToJavaName (cls.getClassVMName ())); |
| countMap.put (packageVMName, count + 1); |
| } |
| } |
| } |
| |
| m_log.info ("showing up to " + MAX_DEBUG_INFO_WARNING_COUNT + " classes without full debug info per package:"); |
| for (Iterator /* String */ names = sampleClassNames.iterator (); names.hasNext (); ) |
| { |
| m_log.info (" " + names.next ()); |
| } |
| } |
| |
| if (bailOut) |
| { |
| // TODO: error code |
| throw new EMMARuntimeException ("BAILED OUT"); |
| } |
| |
| final IItemMetadata [] allTypes = IItemMetadata.Factory.getAllTypes (); |
| m_typeSortComparators = new ItemComparator [allTypes.length]; |
| |
| for (int t = 0; t < allTypes.length; ++ t) |
| { |
| final IntVector orderedAttrIDsWithDir = new IntVector (); |
| final long typeAttrIDSet = allTypes [t].getAttributeIDs (); |
| |
| for (int s = 0; s < m_settings.getSortOrder ().length; s += 2) |
| { |
| final int attrID = m_settings.getSortOrder () [s]; |
| |
| if ((typeAttrIDSet & (1 << attrID)) != 0) |
| { |
| orderedAttrIDsWithDir.add (attrID); |
| |
| final int dir = m_settings.getSortOrder () [s + 1]; |
| orderedAttrIDsWithDir.add (dir); |
| } |
| } |
| |
| // Original: |
| // int [] attributeIDsWithDir = orderedAttrIDsWithDir.values (); |
| |
| // Modified by Buck so that the leftmost column is alphabetized in an HTML report: |
| int [] attributeIDsWithDir = new int[] { IItemAttribute.ATTRIBUTE_NAME_ID, 0 }; |
| |
| m_typeSortComparators [t] = ItemComparator.Factory.create (attributeIDsWithDir, m_settings.getUnitsType ()); |
| } |
| |
| m_metrics = new int [allTypes.length]; |
| final IntIntMap metrics = m_settings.getMetrics (); |
| for (int t = 0; t < m_metrics.length; ++ t) |
| { |
| m_metrics [t] = -1; |
| metrics.get (t, m_metrics, t); |
| } |
| |
| final IReportDataModel model = IReportDataModel.Factory.create (mdata, cdata); |
| m_view = model.getView (m_settings.getViewType ()); |
| |
| m_srcView = (m_settings.getViewType () == IReportDataView.HIER_SRC_VIEW); |
| } |
| |
| public void cleanup () |
| { |
| reset (); |
| } |
| |
| // protected: ............................................................. |
| |
| |
| protected void reset () |
| { |
| m_settings = null; |
| m_cache = null; |
| m_view = null; |
| m_srcView = false; |
| |
| //m_typeSortIDs = null; |
| m_typeSortComparators = null; |
| m_metrics = null; |
| |
| m_log = null; |
| } |
| |
| |
| protected ReportProperties.ParsedProperties m_settings; |
| protected SourcePathCache m_cache; |
| protected IReportDataView m_view; |
| protected boolean m_srcView; |
| |
| protected boolean m_hasSrcFileInfo, m_hasLineNumberInfo; |
| protected ItemComparator [] m_typeSortComparators; // m_typeSortComparators [t] is a comparator representing the sort order for item type t |
| protected int [] m_metrics; // -1 means no pass/fail check for this attribute |
| |
| protected Logger m_log; // every report generator is used on a single thread but the logger needs to be run()-scoped |
| protected boolean m_verbose; |
| |
| // package: ............................................................... |
| |
| // private: ............................................................... |
| |
| |
| private static final int MAX_DEBUG_INFO_WARNING_COUNT = 3; // per package |
| |
| } // end of class |
| // ---------------------------------------------------------------------------- |