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.lang.reflect.Method; 029import java.util.Map; 030import java.util.concurrent.ConcurrentHashMap; 031import java.util.logging.Level; 032import java.util.logging.Logger; 033 034 035import net.sourceforge.cobertura.CoverageIgnore; 036import net.sourceforge.cobertura.instrument.pass3.AbstractCodeProvider; 037 038@CoverageIgnore 039public class TouchCollector { 040 private static final Logger logger = Logger.getLogger(TouchCollector.class.getCanonicalName()); 041 /*In fact - concurrentHashset*/ 042 private static Map<Class<?>,Integer> registeredClasses = new ConcurrentHashMap<Class<?>,Integer>(); 043 044 static { 045 ProjectData.getGlobalProjectData(); // To call ProjectData.initialize(); 046 } 047 048 public static synchronized void registerClass(Class<?> classa) { 049 registeredClasses.put(classa,0); 050 } 051 052 public static synchronized void applyTouchesOnProjectData( 053 ProjectData projectData) { 054 logger.fine("=================== START OF REPORT ======================== "); 055 for (Class<?> c : registeredClasses.keySet()) { 056 logger.fine("Report: "+c.getName()); 057 ClassData cd=projectData.getOrCreateClassData(c.getName()); 058 applyTouchesToSingleClassOnProjectData(cd, c); 059 } 060 logger.fine("=================== END OF REPORT ======================== "); 061 } 062 063 private static void applyTouchesToSingleClassOnProjectData(final ClassData classData,final Class<?> c) { 064 logger.finer("----------- "+ c.getCanonicalName() + " ---------------- "); 065 try { 066 Method m0 = c.getDeclaredMethod(AbstractCodeProvider.COBERTURA_GET_AND_RESET_COUNTERS_METHOD_NAME); 067 m0.setAccessible(true); 068 final int[] res=(int[])m0.invoke(null, new Object[]{}); 069 070 LightClassmapListener lightClassmap=new ApplyToClassDataLightClassmapListener(classData,res); 071 Method m = c.getDeclaredMethod(AbstractCodeProvider.COBERTURA_CLASSMAP_METHOD_NAME,LightClassmapListener.class); 072 m.setAccessible(true); 073 m.invoke(null, lightClassmap); 074 } catch (Exception e) { 075 logger.log(Level.SEVERE, "Cannot apply touches", e); 076 } 077 } 078 079 @CoverageIgnore 080 private static class ApplyToClassDataLightClassmapListener implements LightClassmapListener { 081 //private AtomicInteger idProvider=new AtomicInteger(0); 082 private final ClassData classData; 083 private final int[] res; 084 085 private int currentLine=0; 086 private int jumpsInLine=0; 087 private int switchesInLine=0; 088 089 private void updateLine(int new_line){ 090 if(new_line!=currentLine){ 091 currentLine=new_line; 092 jumpsInLine=0; 093 switchesInLine=0; 094 } 095 } 096 097 public ApplyToClassDataLightClassmapListener(ClassData cd,int[] res) { 098 classData=cd; 099 this.res=res; 100 } 101 102 public void setSource(String source) { 103 logger.fine("source: "+source); 104 classData.setSourceFileName(source); 105 106 } 107 108 public void setClazz(Class<?> clazz) { 109 } 110 111 public void putLineTouchPoint(int classLine, int counterId, String methodName, String methodDescription) { 112 updateLine(classLine); 113 LineData ld=classData.addLine(classLine, methodName,methodDescription); 114 ld.touch(res[counterId]); 115 } 116 117 public void putSwitchTouchPoint(int classLine, int maxBranches, int... counterIds) { 118 updateLine(classLine); 119 LineData ld=getOrCreateLine(classLine); 120 int switchId = switchesInLine++; 121 classData.addLineSwitch(classLine,switchId , 0, counterIds.length-2, maxBranches); 122 for(int i=0; i < counterIds.length; i++){ 123 ld.touchSwitch(switchId, i-1, res[counterIds[i]]); 124 } 125 } 126 127 public void putJumpTouchPoint(int classLine, int trueCounterId, int falseCounterId) { 128 updateLine(classLine); 129 LineData ld=getOrCreateLine(classLine); 130 int branchId=jumpsInLine++; 131 classData.addLineJump(classLine, branchId); 132 ld.touchJump(branchId, true, res[trueCounterId]); 133 ld.touchJump(branchId, false, res[falseCounterId]); 134 } 135 136 private LineData getOrCreateLine(int classLine) { 137 LineData ld=classData.getLineData(classLine); 138 if(ld==null){ 139 ld=classData.addLine(classLine, null, null); 140 } 141 return ld; 142 } 143 }; 144}