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: ReportDataModel.java,v 1.1.1.1 2004/05/09 16:57:38 vlad_r Exp $ 8 */ 9package com.vladium.emma.report; 10 11import java.util.HashMap; 12import java.util.Iterator; 13import java.util.Map; 14 15import com.vladium.util.Descriptors; 16import com.vladium.util.asserts.$assert; 17import com.vladium.emma.IAppErrorCodes; 18import com.vladium.emma.EMMARuntimeException; 19import com.vladium.emma.data.ClassDescriptor; 20import com.vladium.emma.data.IMetaData; 21import com.vladium.emma.data.IMetadataConstants; 22import com.vladium.emma.data.ICoverageData; 23import com.vladium.emma.data.MethodDescriptor; 24 25// ---------------------------------------------------------------------------- 26/** 27 * @author Vlad Roubtsov, (C) 2003 28 */ 29final class ReportDataModel implements IReportDataModel 30{ 31 // public: ................................................................ 32 33 34 public synchronized IReportDataView getView (final int viewType) 35 { 36 // TODO: merge the two branches together 37 38 if (viewType >= m_views.length) throw new IllegalArgumentException ("invalid viewType: " + viewType); 39 40 IReportDataView view = m_views [viewType]; 41 42 if (view != null) 43 return view; 44 else 45 { 46 final boolean srcView = viewType == IReportDataView.HIER_SRC_VIEW; 47 48 if (srcView && ! m_mdata.hasSrcFileData ()) 49 throw new IllegalStateException ("source file data view requested for metadata with incomplete SourceFile debug info"); 50 51 final AllItem root = new AllItem (); 52 final Map /* String(pkg name) -> PackageItem */ packageMap = new HashMap (); 53 final Map /* String(pkg-prefixed src file name) -> ClassItem */ srcfileMap = new HashMap (); 54 55 for (Iterator /* ClassDescriptor */ descriptors = m_mdata.iterator (); descriptors.hasNext (); ) 56 { 57 final ClassDescriptor cls = (ClassDescriptor) descriptors.next (); 58 String packageVMName = cls.getPackageVMName (); 59 60 PackageItem packageItem = (PackageItem) packageMap.get (packageVMName); 61 if (packageItem == null) 62 { 63 final String packageName = packageVMName.length () == 0 ? "default package" : Descriptors.vmNameToJavaName (packageVMName); 64 packageItem = new PackageItem (root, packageName, packageVMName); 65 packageMap.put (packageVMName, packageItem); 66 67 root.addChild (packageItem); 68 } 69 70 SrcFileItem srcfileItem = null; 71 if (srcView) 72 { 73 final String srcFileName = cls.getSrcFileName (); 74 if ($assert.ENABLED) $assert.ASSERT (srcFileName != null, "src file name = null"); 75 76 final String fullSrcFileName = Descriptors.combineVMName (packageVMName, srcFileName); 77 78 srcfileItem = (SrcFileItem) srcfileMap.get (fullSrcFileName); 79 if (srcfileItem == null) 80 { 81 srcfileItem = new SrcFileItem (packageItem, srcFileName, fullSrcFileName); 82 srcfileMap.put (fullSrcFileName, srcfileItem); 83 84 packageItem.addChild (srcfileItem); 85 } 86 } 87 88 final ICoverageData.DataHolder data = m_cdata.getCoverage (cls); 89 90 // check metadata and coverage data consistency: 91 92 if (data != null) 93 { 94 if (data.m_stamp != cls.getStamp ()) 95 throw new EMMARuntimeException (IAppErrorCodes.CLASS_STAMP_MISMATCH, 96 new Object [] { Descriptors.vmNameToJavaName (cls.getClassVMName ()) }); 97 } 98 99 final boolean [][] coverage = data != null ? data.m_coverage : null; 100 101 if ($assert.ENABLED) $assert.ASSERT (! srcView || srcfileItem != null, "null srcfileItem"); 102 103 final ClassItem classItem = srcView ? new ClassItem (srcfileItem, cls, coverage) : new ClassItem (packageItem, cls, coverage); 104 final MethodDescriptor [] methods = cls.getMethods (); 105 106 // TODO: handle edge case when all methods of a class have METHOD_NO_BLOCK_DATA set 107 for (int m = 0; m < methods.length; ++ m) 108 { 109 final MethodDescriptor method = methods [m]; 110 111 if ((method.getStatus () & IMetadataConstants.METHOD_NO_BLOCK_DATA) != 0) continue; 112 113 // TODO: wouldn't it be more consistent to simply pass the entire descriptor into MethodItems? (eval mem savings) 114 final MethodItem methodItem = new MethodItem (classItem, m, method.getName (), method.getDescriptor (), method.getFirstLine ()); 115 // TODO: need to fold class's name into a method name prefix for collapsing case [only when it is not the same as the file name] 116 117 classItem.addChild (methodItem); 118 } 119 120 if (srcView) 121 srcfileItem.addChild (classItem); 122 else 123 packageItem.addChild (classItem); 124 } 125 126 view = new ReportDataView (root); 127 128 m_views [viewType] = view; 129 return view; 130 } 131 } 132 133 // protected: ............................................................. 134 135 // package: ............................................................... 136 137 138 ReportDataModel (final IMetaData mdata, final ICoverageData cdata) 139 { 140 if (mdata == null) throw new IllegalArgumentException ("null input: mdata"); 141 if (cdata == null) throw new IllegalArgumentException ("null input: cdata"); 142 143 m_views = new IReportDataView [2]; 144 145 // TODO: report generators work off data model views only; I should deref 146 // mdata and cdata as soon as all possible views have been constructed and cached 147 148 m_mdata = mdata; 149 m_cdata = cdata; 150 } 151 152 // private: ............................................................... 153 154 155 private static final class ReportDataView implements IReportDataView 156 { 157 public IItem getRoot() 158 { 159 return m_root; 160 } 161 162 ReportDataView (final IItem root) 163 { 164 m_root = root; 165 } 166 167 168 private final IItem m_root; 169 170 } // end of nested class 171 172 173 private final IMetaData m_mdata; 174 private final ICoverageData m_cdata; 175 176 private final IReportDataView [] m_views; 177 178} // end of class 179// ----------------------------------------------------------------------------