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
026package net.sourceforge.cobertura.coveragedata;
027
028import java.util.Map;
029import java.util.Map.Entry;
030import java.util.concurrent.ConcurrentHashMap;
031import java.util.concurrent.atomic.AtomicInteger;
032
033import net.sourceforge.cobertura.coveragedata.countermaps.AtomicCounterMap;
034import net.sourceforge.cobertura.coveragedata.countermaps.CounterMap;
035
036public 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}