001: /*
002: * @(#)ClassRecord.java
003: *
004: * Copyright (C) 2002-2003 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.codecoverage.v2.datastore;
028:
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.LinkedList;
032: import java.util.List;
033: import java.util.Map;
034:
035: import net.sourceforge.groboutils.codecoverage.v2.IAnalysisModule;
036: import net.sourceforge.groboutils.codecoverage.v2.util.ClassSignatureUtil;
037:
038: /**
039: * Contains data associated with a parsed class. Each class is associated
040: * with a collection of analysis modules' marks.
041: *
042: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
043: * @version $Date: 2004/04/15 05:48:26 $
044: * @since December 15, 2002
045: */
046: public class ClassRecord {
047: private String className;
048: private long classCRC;
049: private String sourceFileName;
050: private Map methodToIndex;
051: private String[] methodSignatures;
052: private AnalysisModuleSet amSet;
053: private List marks[]; // each index is for the analysis module
054:
055: public ClassRecord(String className, long classCRC,
056: String sourceFileName, String[] methSigs,
057: AnalysisModuleSet ams) {
058: // we can have an empty set of methods.
059: if (className == null || className.length() <= 0
060: || methSigs == null || ams == null
061: || sourceFileName == null) {
062: throw new IllegalArgumentException("No null args.");
063: }
064:
065: this .className = className;
066: this .classCRC = classCRC;
067: this .sourceFileName = sourceFileName;
068: int len = methSigs.length;
069: if (len > Short.MAX_VALUE) {
070: throw new IllegalStateException(
071: "Too many methods. There is a maximum internal count of "
072: + Short.MAX_VALUE + ".");
073: }
074: this .methodSignatures = new String[len];
075: this .methodToIndex = new HashMap();
076: for (int i = 0; i < len; ++i) {
077: if (methSigs[i] == null) {
078: throw new IllegalArgumentException("No null args.");
079: }
080:
081: this .methodSignatures[i] = methSigs[i];
082: this .methodToIndex.put(methSigs[i], new Short((short) i));
083: }
084:
085: // make a copy of the set, so it isn't changed underneath us.
086: this .amSet = new AnalysisModuleSet(ams);
087: len = this .amSet.getAnalysisModuleCount();
088: this .marks = new List[len];
089: for (int i = 0; i < len; ++i) {
090: this .marks[i] = new LinkedList();
091: }
092: }
093:
094: /**
095: * Gets the name of the corresponding class for this record.
096: *
097: * @return the class name.
098: */
099: public String getClassName() {
100: return this .className;
101: }
102:
103: /**
104: * Returns the cyclic redundancy check (CRC) for the class in this record.
105: *
106: * @return the class CRC.
107: */
108: public long getClassCRC() {
109: return this .classCRC;
110: }
111:
112: /**
113: * Returns the implementation-specific class signature for the class this
114: * record refers to. It should be a String which is unique for this class,
115: * even if multiple class files have the same class name (note that if the
116: * class files are identical, it makes perfect sense to return identical
117: * signatures).
118: *
119: * @return the unique signature for the class in this record.
120: */
121: public String getClassSignature() {
122: return ClassSignatureUtil.getInstance().createClassSignature(
123: getClassName(), getClassCRC());
124: }
125:
126: /**
127: * Returns the name of the Java source file.
128: *
129: * @return the source file name
130: */
131: public String getSourceFileName() {
132: return this .sourceFileName;
133: }
134:
135: /**
136: * Returns a copy of the internal analysis module set.
137: *
138: * @return a copy of the set of analysis modules.
139: */
140: public AnalysisModuleSet getAnalysisModuleSet() {
141: return new AnalysisModuleSet(this .amSet);
142: }
143:
144: /**
145: * Returns a list of known method signatures for this class.
146: *
147: * @return all method signatures known for this class, in the correct
148: * sorted order.
149: */
150: public String[] getMethods() {
151: int len = this .methodSignatures.length;
152: String s[] = new String[len];
153: System.arraycopy(this .methodSignatures, 0, s, 0, len);
154: return s;
155: }
156:
157: /**
158: * Returns the index (as a short) for the given method signature. If the
159: * signature is not registered, then <tt>-1</tt> will be returned.
160: *
161: * @param methodSignature the signature to find the corresponding index
162: * for in this class.
163: * @return the index for <tt>methodSignature</tt> if it is in this method,
164: * or <tt>-1</tt> if it is not in the list.
165: * @exception IllegalArgumentException if <tt>methodSignature</tt> is
166: * <tt>null</tt>.
167: */
168: public short getMethodIndex(String methodSignature) {
169: if (methodSignature == null) {
170: throw new IllegalArgumentException("No null args.");
171: }
172: Short i = (Short) this .methodToIndex.get(methodSignature);
173: if (i == null) {
174: return -1;
175: }
176: return i.shortValue();
177: }
178:
179: /**
180: * Returns the total number of method signatures for this class.
181: *
182: * @return the method signature count.
183: */
184: public int getMethodCount() {
185: return this .methodSignatures.length;
186: }
187:
188: /**
189: * Returns the method signature at the given index.
190: *
191: * @param index the index of the method signature to find.
192: * @return the method signature at index <tt>index</tt>.
193: * @exception IllegalArgumentException if <tt>index</tt> is not within the
194: * bounds of [0 .. <tt>getMethodCount()</tt>-1 ].
195: */
196: public String getMethodAt(short index) {
197: int iindex = (int) index;
198: if (iindex < 0 || iindex >= this .methodSignatures.length) {
199: throw new IllegalArgumentException(
200: "Index out of bounds [0.."
201: + this .methodSignatures.length + ")");
202: }
203: return this .methodSignatures[iindex];
204: }
205:
206: /**
207: * Adds a mark record, and ensures that it is unique upon insertion.
208: *
209: * @param mr the new mark to add. Adding this mark will complete its
210: * internal data structure.
211: */
212: public void addMark(MarkRecord mr) {
213: if (mr == null) {
214: throw new IllegalArgumentException("No null args.");
215: }
216: mr.processMark(this , getAnalysisModuleSet());
217: int moduleIndex = (int) mr.getAnalysisModuleIndex();
218:
219: Iterator iter = this .marks[moduleIndex].iterator();
220: boolean add = true;
221: while (iter.hasNext()) {
222: MarkRecord listRecord = (MarkRecord) iter.next();
223: if (listRecord.equals(mr)) {
224: add = false;
225: break;
226: }
227: }
228: if (add) {
229: this .marks[moduleIndex].add(mr);
230: }
231: }
232:
233: public MarkRecord[] getMarksForAnalysisModule(String measureName) {
234: int moduleIndex = (int) this .amSet.getMeasureIndex(measureName);
235: if (moduleIndex < 0 || moduleIndex >= this .marks.length) {
236: throw new IllegalArgumentException(
237: "Unknown analysis module '" + measureName
238: + "' (index = " + moduleIndex + ")");
239: }
240:
241: List list = this .marks[moduleIndex];
242: MarkRecord mr[] = (MarkRecord[]) list
243: .toArray(new MarkRecord[list.size()]);
244: return mr;
245: }
246:
247: public MarkRecord[] getMarksForAnalysisModule(IAnalysisModule am) {
248: return getMarksForAnalysisModule(am.getMeasureName());
249: }
250: }
|