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    }