001/* 002 * Cobertura - http://cobertura.sourceforge.net/ 003 * 004 * Copyright (C) 2003 jcoverage ltd. 005 * Copyright (C) 2005 Mark Doliner 006 * Copyright (C) 2005 Jeremy Thomerson 007 * Copyright (C) 2006 Jiri Mares 008 * 009 * Cobertura is free software; you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published 011 * by the Free Software Foundation; either version 2 of the License, 012 * or (at your option) any later version. 013 * 014 * Cobertura is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 017 * General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with Cobertura; if not, write to the Free Software 021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 022 * USA 023 */ 024 025package net.sourceforge.cobertura.coveragedata; 026 027import java.util.Iterator; 028import java.util.SortedSet; 029import java.util.TreeSet; 030 031import net.sourceforge.cobertura.CoverageIgnore; 032import net.sourceforge.cobertura.util.StringUtil; 033 034@CoverageIgnore 035public class SourceFileData extends CoverageDataContainer 036 implements Comparable<Object> 037{ 038 039 private static final long serialVersionUID = 3; 040 041 private String name; 042 043 /** 044 * @param name In the format, "net/sourceforge/cobertura/coveragedata/SourceFileData.java" 045 */ 046 public SourceFileData(String name) 047 { 048 if (name == null) 049 throw new IllegalArgumentException( 050 "Source file name must be specified."); 051 this.name = name; 052 } 053 054 public void addClassData(ClassData classData) 055 { 056 lock.lock(); 057 try 058 { 059 if (children.containsKey(classData.getBaseName())) 060 throw new IllegalArgumentException("Source file " + this.name 061 + " already contains a class with the name " 062 + classData.getBaseName()); 063 064 // Each key is a class basename, stored as an String object. 065 // Each value is information about the class, stored as a ClassData object. 066 children.put(classData.getBaseName(), classData); 067 } 068 finally 069 { 070 lock.unlock(); 071 } 072 } 073 074 /** 075 * This is required because we implement Comparable. 076 */ 077 public int compareTo(Object o) 078 { 079 if (!o.getClass().equals(SourceFileData.class)) 080 return Integer.MAX_VALUE; 081 return this.name.compareTo(((SourceFileData)o).name); 082 } 083 084 public boolean contains(String name) 085 { 086 lock.lock(); 087 try 088 { 089 return this.children.containsKey(name); 090 } 091 finally 092 { 093 lock.unlock(); 094 } 095 } 096 097 public boolean containsInstrumentationInfo() 098 { 099 lock.lock(); 100 try 101 { 102 // Return false if any of our child ClassData's does not 103 // contain instrumentation info 104 Iterator iter = this.children.values().iterator(); 105 while (iter.hasNext()) 106 { 107 ClassData classData = (ClassData)iter.next(); 108 if (!classData.containsInstrumentationInfo()) 109 return false; 110 } 111 } 112 finally 113 { 114 lock.unlock(); 115 } 116 return true; 117 } 118 119 /** 120 * Returns true if the given object is an instance of the 121 * SourceFileData class, and it contains the same data as this 122 * class. 123 */ 124 public boolean equals(Object obj) 125 { 126 if (this == obj) 127 return true; 128 if ((obj == null) || !(obj.getClass().equals(this.getClass()))) 129 return false; 130 131 SourceFileData sourceFileData = (SourceFileData)obj; 132 getBothLocks(sourceFileData); 133 try 134 { 135 return super.equals(obj) 136 && this.name.equals(sourceFileData.name); 137 } 138 finally 139 { 140 lock.unlock(); 141 sourceFileData.lock.unlock(); 142 } 143 } 144 145 public String getBaseName() 146 { 147 String fullNameWithoutExtension; 148 int lastDot = this.name.lastIndexOf('.'); 149 if (lastDot == -1) 150 { 151 fullNameWithoutExtension = this.name; 152 } 153 else 154 { 155 fullNameWithoutExtension = this.name.substring(0, lastDot); 156 } 157 158 int lastSlash = fullNameWithoutExtension.lastIndexOf('/'); 159 if (lastSlash == -1) 160 { 161 return fullNameWithoutExtension; 162 } 163 return fullNameWithoutExtension.substring(lastSlash + 1); 164 } 165 166 public SortedSet getClasses() 167 { 168 lock.lock(); 169 try 170 { 171 return new TreeSet(this.children.values()); 172 } 173 finally 174 { 175 lock.unlock(); 176 } 177 } 178 179 public LineData getLineCoverage(int lineNumber) 180 { 181 lock.lock(); 182 try 183 { 184 Iterator iter = this.children.values().iterator(); 185 while (iter.hasNext()) 186 { 187 ClassData classData = (ClassData)iter.next(); 188 if (classData.isValidSourceLineNumber(lineNumber)) 189 return classData.getLineCoverage(lineNumber); 190 } 191 } 192 finally 193 { 194 lock.unlock(); 195 } 196 return null; 197 } 198 199 public String getName() 200 { 201 return this.name; 202 } 203 204 /** 205 * @return The name of this source file without the file extension 206 * in the format 207 * "net.sourceforge.cobertura.coveragedata.SourceFileData" 208 */ 209 public String getNormalizedName() 210 { 211 String fullNameWithoutExtension; 212 int lastDot = this.name.lastIndexOf('.'); 213 if (lastDot == -1) 214 { 215 fullNameWithoutExtension = this.name; 216 } 217 else 218 { 219 fullNameWithoutExtension = this.name.substring(0, lastDot); 220 } 221 222 return StringUtil.replaceAll(fullNameWithoutExtension, "/", "."); 223 } 224 225 /** 226 * @return The name of the package that this source file is in. 227 * In the format "net.sourceforge.cobertura.coveragedata" 228 */ 229 public String getPackageName() 230 { 231 int lastSlash = this.name.lastIndexOf('/'); 232 if (lastSlash == -1) 233 { 234 return null; 235 } 236 return StringUtil.replaceAll(this.name.substring(0, lastSlash), "/", 237 "."); 238 } 239 240 public int hashCode() 241 { 242 return this.name.hashCode(); 243 } 244 245 public boolean isValidSourceLineNumber(int lineNumber) 246 { 247 lock.lock(); 248 try 249 { 250 Iterator iter = this.children.values().iterator(); 251 while (iter.hasNext()) 252 { 253 ClassData classData = (ClassData)iter.next(); 254 if (classData.isValidSourceLineNumber(lineNumber)) 255 return true; 256 } 257 } 258 finally 259 { 260 lock.unlock(); 261 } 262 return false; 263 } 264 265}