• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: MetaData.java,v 1.1.1.1.2.2 2004/07/16 23:32:29 vlad_r Exp $
8  */
9 package com.vladium.emma.data;
10 
11 import java.io.DataInput;
12 import java.io.DataOutput;
13 import java.io.IOException;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.Map;
18 
19 import com.vladium.logging.Logger;
20 import com.vladium.util.asserts.$assert;
21 
22 // ----------------------------------------------------------------------------
23 /*
24  * Average mem size/class entry: 6166 bytes [1.4.1, rt.jar], 5764 bytes [1.3.1, rt.jar]
25  */
26 /**
27  * @author Vlad Roubtsov, (C) 2003
28  */
29 final class MetaData implements IMetaData, Cloneable
30 {
31     // public: ................................................................
32 
33     // TODO: MT-safety model
34 
35     // TODO: no duplicate detection is done here at the moment
36     // [may require supporting fast lookup for already added descriptors]
37 
shallowCopy()38     public IMetaData shallowCopy ()
39     {
40         final MetaData _clone;
41         try
42         {
43             _clone = (MetaData) super.clone ();
44         }
45         catch (CloneNotSupportedException cnse)
46         {
47             throw new Error (cnse.toString ());
48         }
49 
50         final HashMap _classMap;
51 
52         synchronized (lock ())
53         {
54             _classMap = (HashMap) m_classMap.clone ();
55         }
56 
57         // [m_packagesWarned is not cloned by design]
58 
59         _clone.m_classMap = _classMap;
60 
61         return _clone;
62     }
63 
getOptions()64     public CoverageOptions getOptions ()
65     {
66         return m_options;
67     }
68 
size()69     public int size ()
70     {
71         return m_classMap.size ();
72     }
73 
hasSrcFileData()74     public boolean hasSrcFileData ()
75     {
76         return m_hasSrcFileInfo;
77     }
78 
hasLineNumberData()79     public boolean hasLineNumberData ()
80     {
81         return m_hasLineNumberInfo;
82     }
83 
iterator()84     public Iterator iterator ()
85     {
86         return m_classMap.values ().iterator ();
87     }
88 
89 //    public boolean hasDescriptor (final ClassDescriptor cls)
90 //    {
91 //        if ($assert.ENABLED) $assert.ASSERT (cls != null, "cls is null");
92 //
93 //        return m_classes.contains (cls);
94 //    }
95 
hasDescriptor(final String classVMName)96     public boolean hasDescriptor (final String classVMName)
97     {
98         if ($assert.ENABLED) $assert.ASSERT (classVMName != null, "className is null");
99 
100         return m_classMap.containsKey (classVMName);
101     }
102 
lock()103     public Object lock ()
104     {
105         return m_classMap;
106     }
107 
add(final ClassDescriptor cls, final boolean overwrite)108     public boolean add (final ClassDescriptor cls, final boolean overwrite)
109     {
110         if ($assert.ENABLED) $assert.ASSERT (cls != null, "cls is null");
111 
112         final String classVMName = cls.getClassVMName ();
113 
114         if (overwrite || ! m_classMap.containsKey (classVMName))
115         {
116             m_classMap.put (classVMName, cls);
117 
118             boolean incompleteDebugInfo = false;
119 
120             if (! cls.hasSrcFileInfo ())
121             {
122                 m_hasSrcFileInfo = false;
123                 incompleteDebugInfo = true;
124             }
125 
126             if (! cls.hasCompleteLineNumberInfo ())
127             {
128                 m_hasLineNumberInfo = false;
129                 incompleteDebugInfo = true;
130             }
131 
132             // SF FR 971176: provide user with sample classes that may later
133             // caused warnings about line coverage not available
134 
135             if (incompleteDebugInfo)
136             {
137                 final Logger log = Logger.getLogger ();
138 
139                 if (log.atINFO ())
140                 {
141                     final String packageVMName = cls.getPackageVMName ();
142 
143                     if (m_packagesWarned.add (packageVMName))
144                     {
145                         log.info ("package [" + packageVMName + "] contains classes [" + cls.getName () + "] without full debug info");
146                     }
147                 }
148             }
149 
150             return true;
151         }
152 
153         return false;
154     }
155 
156     // IMergeable:
157 
isEmpty()158     public boolean isEmpty ()
159     {
160         return m_classMap.isEmpty ();
161     }
162 
163     /*
164      * note: rhs entries must override current entries
165      */
merge(final IMergeable rhs)166     public IMergeable merge (final IMergeable rhs)
167     {
168         if ((rhs == null) || rhs.isEmpty () || (rhs == this))
169             return this;
170         else
171         {
172             final MetaData rhsmdata = (MetaData) rhs; // TODO: redesign to avoid this cast?
173             final Map rhsclasses = rhsmdata.m_classMap;
174 
175             // rhs entries always override existing content:
176 
177             for (Iterator entries = rhsclasses.entrySet ().iterator (); entries.hasNext (); )
178             {
179                 final Map.Entry entry = (Map.Entry) entries.next ();
180 
181                 final String classVMName = (String) entry.getKey ();
182                 final Object rhsdescriptor = entry.getValue ();
183 
184                 m_classMap.put (classVMName, rhsdescriptor);
185             }
186 
187             // update debug info flags if necessary:
188 
189             if (! rhsmdata.hasSrcFileData ()) m_hasSrcFileInfo = false;
190             if (! rhsmdata.hasLineNumberData ()) m_hasLineNumberInfo = false;
191 
192             return this;
193         }
194     }
195 
196     // protected: .............................................................
197 
198     // package: ...............................................................
199 
200 
MetaData(final CoverageOptions options)201     MetaData (final CoverageOptions options)
202     {
203         if ($assert.ENABLED) $assert.ASSERT (options != null, "options is null");
204         m_options = options;
205 
206         m_hasSrcFileInfo = true;
207         m_hasLineNumberInfo = true;
208 
209         m_classMap = new HashMap ();
210         m_packagesWarned = new HashSet ();
211     }
212 
213 
readExternal(final DataInput in)214     static MetaData readExternal (final DataInput in)
215         throws IOException
216     {
217         final CoverageOptions options = CoverageOptions.readExternal (in);
218 
219         final boolean hasSrcFileInfo = in.readBoolean ();
220         final boolean hasLineNumberInfo = in.readBoolean ();
221 
222         final int size = in.readInt ();
223         final HashMap classMap = new HashMap (size);
224 
225         for (int i = 0; i < size; ++ i)
226         {
227             final String classVMName = in.readUTF ();
228             final ClassDescriptor cls = ClassDescriptor.readExternal (in);
229 
230             classMap.put (classVMName, cls);
231         }
232 
233         // [m_packagesWarned is not part of persisted state]
234 
235         return new MetaData (options, classMap, hasSrcFileInfo, hasLineNumberInfo);
236     }
237 
writeExternal(final MetaData mdata, final DataOutput out)238     static void writeExternal (final MetaData mdata, final DataOutput out)
239         throws IOException
240     {
241         CoverageOptions.writeExternal (mdata.m_options, out);
242 
243         out.writeBoolean (mdata.m_hasSrcFileInfo);
244         out.writeBoolean (mdata.m_hasLineNumberInfo);
245 
246         final Map classMap = mdata.m_classMap;
247 
248         final int size = classMap.size ();
249         out.writeInt (size); // too bad the capacity is not visible
250 
251         final Iterator entries = classMap.entrySet ().iterator ();
252         for (int i = 0; i < size; ++ i)
253         {
254             final Map.Entry entry = (Map.Entry) entries.next ();
255 
256             final String classVMName = (String) entry.getKey ();
257             final ClassDescriptor cls = (ClassDescriptor) entry.getValue ();
258 
259             out.writeUTF (classVMName);
260             ClassDescriptor.writeExternal (cls, out);
261         }
262 
263         // [m_packagesWarned is not part of persisted state]
264     }
265 
266     // private: ...............................................................
267 
268 
MetaData(final CoverageOptions options, final HashMap classMap, final boolean hasSrcFileInfo, final boolean hasLineNumberInfo)269     private MetaData (final CoverageOptions options, final HashMap classMap,
270                       final boolean hasSrcFileInfo, final boolean hasLineNumberInfo)
271     {
272         if ($assert.ENABLED) $assert.ASSERT (options != null, "options is null");
273         m_options = options;
274 
275         m_hasSrcFileInfo = hasSrcFileInfo;
276         m_hasLineNumberInfo = hasLineNumberInfo;
277 
278         m_classMap = classMap;
279     }
280 
281 
282     private final CoverageOptions m_options; // [never null]
283     private boolean m_hasSrcFileInfo, m_hasLineNumberInfo;
284     private /*final*/ HashMap /* classVMName:String->ClassDescriptor */ m_classMap; // [never null]
285 
286     private /*final*/ transient HashSet /*  packageVMName:String */ m_packagesWarned; // [never null]
287 
288 } // end of class
289 // ----------------------------------------------------------------------------