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// ----------------------------------------------------------------------------