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 022package net.sourceforge.cobertura.coveragedata; 023 024import java.io.IOException; 025import java.io.ObjectInputStream; 026import java.io.Serializable; 027import java.util.concurrent.locks.Lock; 028import java.util.concurrent.locks.ReentrantLock; 029 030import net.sourceforge.cobertura.CoverageIgnore; 031 032/** 033 */ 034@CoverageIgnore 035public class JumpData implements BranchCoverageData, Comparable<Object>, Serializable 036{ 037 private static final long serialVersionUID = 8; 038 039 protected transient Lock lock; 040 041 private int conditionNumber; 042 043 private long trueHits; 044 045 private long falseHits; 046 047 JumpData(int conditionNumber) 048 { 049 super(); 050 this.conditionNumber = conditionNumber; 051 this.trueHits = 0L; 052 this.falseHits = 0L; 053 initLock(); 054 } 055 056 private void initLock() 057 { 058 lock = new ReentrantLock(); 059 } 060 061 public int compareTo(Object o) 062 { 063 if (!o.getClass().equals(JumpData.class)) 064 return Integer.MAX_VALUE; 065 return this.conditionNumber - ((JumpData) o).conditionNumber; 066 } 067 068 void touchBranch(boolean branch,int new_hits) 069 { 070 lock.lock(); 071 try 072 { 073 if (branch) 074 { 075 this.trueHits+=new_hits; 076 } 077 else 078 { 079 this.falseHits+=new_hits; 080 } 081 } 082 finally 083 { 084 lock.unlock(); 085 } 086 } 087 088 public int getConditionNumber() 089 { 090 return this.conditionNumber; 091 } 092 093 public long getTrueHits() 094 { 095 lock.lock(); 096 try 097 { 098 return this.trueHits; 099 } 100 finally 101 { 102 lock.unlock(); 103 } 104 } 105 106 public long getFalseHits() 107 { 108 lock.lock(); 109 try 110 { 111 return this.falseHits; 112 } 113 finally 114 { 115 lock.unlock(); 116 } 117 } 118 119 public double getBranchCoverageRate() 120 { 121 lock.lock(); 122 try 123 { 124 return ((double) getNumberOfCoveredBranches()) / getNumberOfValidBranches(); 125 } 126 finally 127 { 128 lock.unlock(); 129 } 130 } 131 132 public boolean equals(Object obj) 133 { 134 if (this == obj) 135 return true; 136 if ((obj == null) || !(obj.getClass().equals(this.getClass()))) 137 return false; 138 139 JumpData branchData = (JumpData) obj; 140 getBothLocks(branchData); 141 try 142 { 143 return (this.trueHits == branchData.trueHits) 144 && (this.falseHits == branchData.falseHits) 145 && (this.conditionNumber == branchData.conditionNumber); 146 } 147 finally 148 { 149 lock.unlock(); 150 branchData.lock.unlock(); 151 } 152 } 153 154 public int hashCode() 155 { 156 return this.conditionNumber; 157 } 158 159 public int getNumberOfCoveredBranches() 160 { 161 lock.lock(); 162 try 163 { 164 return ((trueHits > 0) ? 1 : 0) + ((falseHits > 0) ? 1: 0); 165 } 166 finally 167 { 168 lock.unlock(); 169 } 170 } 171 172 public int getNumberOfValidBranches() 173 { 174 return 2; 175 } 176 177 public void merge(BranchCoverageData coverageData) 178 { 179 JumpData jumpData = (JumpData) coverageData; 180 getBothLocks(jumpData); 181 try 182 { 183 this.trueHits += jumpData.trueHits; 184 this.falseHits += jumpData.falseHits; 185 } 186 finally 187 { 188 lock.unlock(); 189 jumpData.lock.unlock(); 190 } 191 } 192 193 private void getBothLocks(JumpData other) { 194 /* 195 * To prevent deadlock, we need to get both locks or none at all. 196 * 197 * When this method returns, the thread will have both locks. 198 * Make sure you unlock them! 199 */ 200 boolean myLock = false; 201 boolean otherLock = false; 202 while ((!myLock) || (!otherLock)) 203 { 204 try 205 { 206 myLock = lock.tryLock(); 207 otherLock = other.lock.tryLock(); 208 } 209 finally 210 { 211 if ((!myLock) || (!otherLock)) 212 { 213 //could not obtain both locks - so unlock the one we got. 214 if (myLock) 215 { 216 lock.unlock(); 217 } 218 if (otherLock) 219 { 220 other.lock.unlock(); 221 } 222 //do a yield so the other threads will get to work. 223 Thread.yield(); 224 } 225 } 226 } 227 } 228 229 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException 230 { 231 in.defaultReadObject(); 232 initLock(); 233 } 234 235}