001 /*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2010 Piotr Tabor
005 *
006 * Note: This file is dual licensed under the GPL and the Apache
007 * Source License (so that it can be used from both the main
008 * Cobertura classes and the ant tasks).
009 *
010 * Cobertura is free software; you can redistribute it and/or modify
011 * it under the terms of the GNU General Public License as published
012 * by the Free Software Foundation; either version 2 of the License,
013 * or (at your option) any later version.
014 *
015 * Cobertura is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of
017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018 * General Public License for more details.
019 *
020 * You should have received a copy of the GNU General Public License
021 * along with Cobertura; if not, write to the Free Software
022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
023 * USA
024 */
025
026 package net.sourceforge.cobertura.coveragedata;
027
028 import java.util.Map;
029 import java.util.Map.Entry;
030 import java.util.concurrent.ConcurrentHashMap;
031 import java.util.concurrent.atomic.AtomicInteger;
032
033 import net.sourceforge.cobertura.coveragedata.countermaps.AtomicCounterMap;
034 import net.sourceforge.cobertura.coveragedata.countermaps.CounterMap;
035
036 public class TouchCollector implements HasBeenInstrumented{
037
038 private static final CounterMap<LineTouchData> touchedLines=new AtomicCounterMap<LineTouchData>();
039 private static final CounterMap<SwitchTouchData> switchTouchData=new AtomicCounterMap<SwitchTouchData>();
040 private static final CounterMap<JumpTouchData> jumpTouchData=new AtomicCounterMap<JumpTouchData>();
041
042 private static AtomicInteger lastClassId=new AtomicInteger(1);
043 private static final Map<String,Integer> class2classId=new ConcurrentHashMap<String, Integer>();
044 private static final Map<Integer,String> classId2class=new ConcurrentHashMap<Integer,String>();
045
046 static{
047 ProjectData.initialize();
048 }
049
050 private static final int registerClassData(String name){
051 Integer res=class2classId.get(name);
052 if (res==null){
053 int new_id=lastClassId.incrementAndGet();
054 class2classId.put(name, new_id);
055 classId2class.put(new_id, name);
056 return new_id;
057 }
058 return res;
059 }
060
061 /**
062 * This method is only called by code that has been instrumented. It
063 * is not called by any of the Cobertura code or ant tasks.
064 */
065 public static final void touchSwitch(String classId,int lineNumber, int switchNumber, int branch) {
066 switchTouchData.incrementValue(new SwitchTouchData(registerClassData(classId),lineNumber, switchNumber, branch));
067 }
068
069 /**
070 * This method is only called by code that has been instrumented. It
071 * is not called by any of the Cobertura code or ant tasks.
072 */
073 public static final void touch(String classId,int lineNumber) {
074 touchedLines.incrementValue(new LineTouchData(registerClassData(classId), lineNumber));
075 }
076
077 /**
078 * This method is only called by code that has been instrumented. It
079 * is not called by any of the Cobertura code or ant tasks.
080 */
081 public static final void touchJump(String classId,int lineNumber, int branchNumber, boolean branch) {
082 jumpTouchData.incrementValue(new JumpTouchData(registerClassData(classId),lineNumber, branchNumber, branch));
083 }
084
085 private static class LineTouchData implements HasBeenInstrumented{
086 int classId,lineNumber;
087 public LineTouchData(int classId,int lineNumber) {
088 this.classId=classId;
089 this.lineNumber=lineNumber;
090 }
091 @Override
092 public int hashCode() {
093 final int prime = 31;
094 int result = 1;
095 result = prime * result + classId;
096 result = prime * result + lineNumber;
097 return result;
098 }
099 @Override
100 public boolean equals(Object obj) {
101 if (this == obj)
102 return true;
103 if (obj == null)
104 return false;
105 if (getClass() != obj.getClass())
106 return false;
107 LineTouchData other = (LineTouchData) obj;
108 if (classId != other.classId)
109 return false;
110 if (lineNumber != other.lineNumber)
111 return false;
112 return true;
113 }
114 }
115
116 private static class SwitchTouchData extends LineTouchData implements HasBeenInstrumented{
117 int switchNumber, branch;
118
119 public SwitchTouchData(int classId,int lineNumber, int switchNumber, int branch) {
120 super(classId,lineNumber);
121 this.switchNumber=switchNumber;
122 this.branch=branch;
123 }
124
125 @Override
126 public int hashCode() {
127 final int prime = 31;
128 int result = super.hashCode();
129 result = prime * result + branch;
130 result = prime * result + switchNumber;
131 return result;
132 }
133
134 @Override
135 public boolean equals(Object obj) {
136 if (this == obj)
137 return true;
138 if (!super.equals(obj))
139 return false;
140 if (getClass() != obj.getClass())
141 return false;
142 SwitchTouchData other = (SwitchTouchData) obj;
143 if (branch != other.branch)
144 return false;
145 if (switchNumber != other.switchNumber)
146 return false;
147 return true;
148 }
149 }
150
151 private static class JumpTouchData extends LineTouchData implements HasBeenInstrumented{
152 int branchNumber;
153 boolean branch;
154 public JumpTouchData(int classId,int lineNumber, int branchNumber, boolean branch) {
155 super(classId, lineNumber);
156 this.branchNumber=branchNumber;
157 this.branch=branch;
158 }
159 @Override
160 public int hashCode() {
161 final int prime = 31;
162 int result = super.hashCode();
163 result = prime * result + (branch ? 1231 : 1237);
164 result = prime * result + branchNumber;
165 return result;
166 }
167 @Override
168 public boolean equals(Object obj) {
169 if (this == obj)
170 return true;
171 if (!super.equals(obj))
172 return false;
173 if (getClass() != obj.getClass())
174 return false;
175 JumpTouchData other = (JumpTouchData) obj;
176 if (branch != other.branch)
177 return false;
178 if (branchNumber != other.branchNumber)
179 return false;
180 return true;
181 }
182 }
183
184
185 public static synchronized void applyTouchesOnProjectData(ProjectData projectData){
186 System.out.println("Flushing results...");
187 Map<LineTouchData,Integer> touches=touchedLines.getFinalStateAndCleanIt();
188 for(Entry<LineTouchData, Integer> touch:touches.entrySet()){
189 if(touch.getValue()>0){
190 getClassFor(touch.getKey(),projectData).touch(touch.getKey().lineNumber,touch.getValue());
191 }
192 }
193
194 Map<SwitchTouchData,Integer> switchTouches=switchTouchData.getFinalStateAndCleanIt();
195 for(Entry<SwitchTouchData, Integer> touch:switchTouches.entrySet()){
196 if(touch.getValue()>0){
197 getClassFor(touch.getKey(),projectData).touchSwitch(
198 touch.getKey().lineNumber,
199 touch.getKey().switchNumber,
200 touch.getKey().branch,touch.getValue());
201 }
202 }
203
204 Map<JumpTouchData,Integer> jumpTouches=jumpTouchData.getFinalStateAndCleanIt();
205 for(Entry<JumpTouchData, Integer> touch:jumpTouches.entrySet()){
206 if(touch.getValue()>0){
207 getClassFor(touch.getKey(),projectData).touchJump(
208 touch.getKey().lineNumber,
209 touch.getKey().branchNumber,
210 touch.getKey().branch,touch.getValue());
211 }
212 }
213 System.out.println("Flushing results done");
214 }
215
216 private static ClassData getClassFor(LineTouchData key,ProjectData projectData) {
217 // System.out.println("\nLooking for:"+key.classId+"\n");
218 return projectData.getOrCreateClassData(classId2class.get(key.classId));
219 }
220
221 }