001 /* 002 * Cobertura - http://cobertura.sourceforge.net/ 003 * 004 * Copyright (C) 2006 Jiri Mares 005 * 006 * Cobertura is free software; you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published 008 * by the Free Software Foundation; either version 2 of the License, 009 * or (at your option) any later version. 010 * 011 * Cobertura is distributed in the hope that it will be useful, but 012 * WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Cobertura; if not, write to the Free Software 018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 019 * USA 020 */ 021 022 package net.sourceforge.cobertura.coveragedata; 023 024 import java.io.IOException; 025 import java.io.ObjectInputStream; 026 import java.io.Serializable; 027 import java.util.concurrent.locks.Lock; 028 import java.util.concurrent.locks.ReentrantLock; 029 030 /** 031 * <p> 032 * This class implements HasBeenInstrumented so that when cobertura instruments 033 * itself, it will omit this class. It does this to avoid an infinite recursion 034 * problem because instrumented classes make use of this class. 035 * </p> 036 */ 037 public class JumpData implements BranchCoverageData, Comparable, Serializable, 038 HasBeenInstrumented 039 { 040 private static final long serialVersionUID = 8; 041 042 protected transient Lock lock; 043 044 private int conditionNumber; 045 046 private long trueHits; 047 048 private long falseHits; 049 050 JumpData(int conditionNumber) 051 { 052 super(); 053 this.conditionNumber = conditionNumber; 054 this.trueHits = 0L; 055 this.falseHits = 0L; 056 initLock(); 057 } 058 059 private void initLock() 060 { 061 lock = new ReentrantLock(); 062 } 063 064 public int compareTo(Object o) 065 { 066 if (!o.getClass().equals(JumpData.class)) 067 return Integer.MAX_VALUE; 068 return this.conditionNumber - ((JumpData) o).conditionNumber; 069 } 070 071 void touchBranch(boolean branch) 072 { 073 lock.lock(); 074 try 075 { 076 if (branch) 077 { 078 this.trueHits++; 079 } 080 else 081 { 082 this.falseHits++; 083 } 084 } 085 finally 086 { 087 lock.unlock(); 088 } 089 } 090 091 public int getConditionNumber() 092 { 093 return this.conditionNumber; 094 } 095 096 public long getTrueHits() 097 { 098 lock.lock(); 099 try 100 { 101 return this.trueHits; 102 } 103 finally 104 { 105 lock.unlock(); 106 } 107 } 108 109 public long getFalseHits() 110 { 111 lock.lock(); 112 try 113 { 114 return this.falseHits; 115 } 116 finally 117 { 118 lock.unlock(); 119 } 120 } 121 122 public double getBranchCoverageRate() 123 { 124 lock.lock(); 125 try 126 { 127 return ((double) getNumberOfCoveredBranches()) / getNumberOfValidBranches(); 128 } 129 finally 130 { 131 lock.unlock(); 132 } 133 } 134 135 public boolean equals(Object obj) 136 { 137 if (this == obj) 138 return true; 139 if ((obj == null) || !(obj.getClass().equals(this.getClass()))) 140 return false; 141 142 JumpData branchData = (JumpData) obj; 143 getBothLocks(branchData); 144 try 145 { 146 return (this.trueHits == branchData.trueHits) 147 && (this.falseHits == branchData.falseHits) 148 && (this.conditionNumber == branchData.conditionNumber); 149 } 150 finally 151 { 152 lock.unlock(); 153 branchData.lock.unlock(); 154 } 155 } 156 157 public int hashCode() 158 { 159 return this.conditionNumber; 160 } 161 162 public int getNumberOfCoveredBranches() 163 { 164 lock.lock(); 165 try 166 { 167 return ((trueHits > 0) ? 1 : 0) + ((falseHits > 0) ? 1: 0); 168 } 169 finally 170 { 171 lock.unlock(); 172 } 173 } 174 175 public int getNumberOfValidBranches() 176 { 177 return 2; 178 } 179 180 public void merge(BranchCoverageData coverageData) 181 { 182 JumpData jumpData = (JumpData) coverageData; 183 getBothLocks(jumpData); 184 try 185 { 186 this.trueHits += jumpData.trueHits; 187 this.falseHits += jumpData.falseHits; 188 } 189 finally 190 { 191 lock.unlock(); 192 jumpData.lock.unlock(); 193 } 194 } 195 196 private void getBothLocks(JumpData other) { 197 /* 198 * To prevent deadlock, we need to get both locks or none at all. 199 * 200 * When this method returns, the thread will have both locks. 201 * Make sure you unlock them! 202 */ 203 boolean myLock = false; 204 boolean otherLock = false; 205 while ((!myLock) || (!otherLock)) 206 { 207 try 208 { 209 myLock = lock.tryLock(); 210 otherLock = other.lock.tryLock(); 211 } 212 finally 213 { 214 if ((!myLock) || (!otherLock)) 215 { 216 //could not obtain both locks - so unlock the one we got. 217 if (myLock) 218 { 219 lock.unlock(); 220 } 221 if (otherLock) 222 { 223 other.lock.unlock(); 224 } 225 //do a yield so the other threads will get to work. 226 Thread.yield(); 227 } 228 } 229 } 230 } 231 232 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException 233 { 234 in.defaultReadObject(); 235 initLock(); 236 } 237 238 }