Coverage Report - net.sourceforge.cobertura.coveragedata.ProjectData
 
Classes in this File Line Coverage Branch Coverage Complexity
ProjectData
N/A
N/A
2.071
 
 1  
 /*
 2  
  * Cobertura - http://cobertura.sourceforge.net/
 3  
  *
 4  
  * Copyright (C) 2003 jcoverage ltd.
 5  
  * Copyright (C) 2005 Mark Doliner
 6  
  * Copyright (C) 2005 Grzegorz Lukasik
 7  
  * Copyright (C) 2005 Björn Beskow
 8  
  * Copyright (C) 2006 John Lewis
 9  
  *
 10  
  * Cobertura is free software; you can redistribute it and/or modify
 11  
  * it under the terms of the GNU General Public License as published
 12  
  * by the Free Software Foundation; either version 2 of the License,
 13  
  * or (at your option) any later version.
 14  
  *
 15  
  * Cobertura is distributed in the hope that it will be useful, but
 16  
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 17  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 18  
  * General Public License for more details.
 19  
  *
 20  
  * You should have received a copy of the GNU General Public License
 21  
  * along with Cobertura; if not, write to the Free Software
 22  
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 23  
  * USA
 24  
  */
 25  
 
 26  
 package net.sourceforge.cobertura.coveragedata;
 27  
 
 28  
 import java.io.File;
 29  
 import java.util.Collection;
 30  
 import java.util.Collections;
 31  
 import java.util.HashMap;
 32  
 import java.util.Iterator;
 33  
 import java.util.Map;
 34  
 import java.util.SortedSet;
 35  
 import java.util.TreeSet;
 36  
 
 37  
 import net.sourceforge.cobertura.util.FileLocker;
 38  
 
 39  
 public class ProjectData extends CoverageDataContainer implements HasBeenInstrumented
 40  
 {
 41  
 
 42  
         private static final long serialVersionUID = 6;
 43  
 
 44  
         private static ProjectData globalProjectData = null;
 45  
 
 46  
         private static SaveTimer saveTimer = null;
 47  
 
 48  
         /** This collection is used for quicker access to the list of classes. */
 49  
         private Map classes = Collections.synchronizedMap(new HashMap());
 50  
 
 51  
         public void addClassData(ClassData classData)
 52  
         {
 53  
                 String packageName = classData.getPackageName();
 54  
                 PackageData packageData = (PackageData)children.get(packageName);
 55  
                 if (packageData == null)
 56  
                 {
 57  
                         packageData = new PackageData(packageName);
 58  
                         // Each key is a package name, stored as an String object.
 59  
                         // Each value is information about the package, stored as a PackageData object.
 60  
                         this.children.put(packageName, packageData);
 61  
                 }
 62  
                 packageData.addClassData(classData);
 63  
                 this.classes.put(classData.getName(), classData);
 64  
         }
 65  
 
 66  
         public ClassData getClassData(String name)
 67  
         {
 68  
                 return (ClassData)this.classes.get(name);
 69  
         }
 70  
 
 71  
         /**
 72  
          * This is called by instrumented bytecode.
 73  
          */
 74  
         public synchronized ClassData getOrCreateClassData(String name)
 75  
         {
 76  
                 ClassData classData = (ClassData)this.classes.get(name);
 77  
                 if (classData == null)
 78  
                 {
 79  
                         classData = new ClassData(name);
 80  
                         addClassData(classData);
 81  
                 }
 82  
                 return classData;
 83  
         }
 84  
 
 85  
         public Collection getClasses()
 86  
         {
 87  
                 return this.classes.values();
 88  
         }
 89  
 
 90  
         public int getNumberOfClasses()
 91  
         {
 92  
                 return this.classes.size();
 93  
         }
 94  
 
 95  
         public int getNumberOfSourceFiles()
 96  
         {
 97  
                 return getSourceFiles().size();
 98  
         }
 99  
 
 100  
         public SortedSet getPackages()
 101  
         {
 102  
                 return new TreeSet(this.children.values());
 103  
         }
 104  
 
 105  
         public Collection getSourceFiles()
 106  
         {
 107  
                 SortedSet sourceFileDatas = new TreeSet();
 108  
                 Iterator iter = this.children.values().iterator();
 109  
                 while (iter.hasNext())
 110  
                 {
 111  
                         PackageData packageData = (PackageData)iter.next();
 112  
                         sourceFileDatas.addAll(packageData.getSourceFiles());
 113  
                 }
 114  
                 return sourceFileDatas;
 115  
         }
 116  
 
 117  
         /**
 118  
          * Get all subpackages of the given package. Includes also specified package if
 119  
          * it exists.
 120  
          *
 121  
          * @param packageName The package name to find subpackages for.
 122  
          *        For example, "com.example"
 123  
          * @return A collection containing PackageData objects.  Each one
 124  
          *         has a name beginning with the given packageName.  For
 125  
          *         example: "com.example.io", "com.example.io.internal"
 126  
          */
 127  
         public SortedSet getSubPackages(String packageName)
 128  
         {
 129  
                 SortedSet subPackages = new TreeSet();
 130  
                 Iterator iter = this.children.values().iterator();
 131  
                 while (iter.hasNext())
 132  
                 {
 133  
                         PackageData packageData = (PackageData)iter.next();
 134  
                         if (packageData.getName().startsWith(packageName))
 135  
                                 subPackages.add(packageData);
 136  
                 }
 137  
                 return subPackages;
 138  
         }
 139  
 
 140  
         public void merge(CoverageData coverageData)
 141  
         {
 142  
                 super.merge(coverageData);
 143  
 
 144  
                 ProjectData projectData = (ProjectData)coverageData;
 145  
                 for (Iterator iter = projectData.classes.keySet().iterator(); iter.hasNext();)
 146  
                 {
 147  
                         Object key = iter.next();
 148  
                         if (!this.classes.containsKey(key))
 149  
                         {
 150  
                                 this.classes.put(key, projectData.classes.get(key));
 151  
                         }
 152  
                 }
 153  
         }
 154  
 
 155  
         /**
 156  
          * Get a reference to a ProjectData object in order to increase the
 157  
          * coverage count for a specific line.
 158  
          *
 159  
          * This method is only called by code that has been instrumented.  It
 160  
          * is not called by any of the Cobertura code or ant tasks.
 161  
          */
 162  
         public static ProjectData getGlobalProjectData()
 163  
         {
 164  
                 if (globalProjectData != null)
 165  
                         return globalProjectData;
 166  
 
 167  
                 globalProjectData = new ProjectData();
 168  
                 initialize();
 169  
                 return globalProjectData;
 170  
         }
 171  
 
 172  
         // TODO: Is it possible to do this as a static initializer?
 173  
         private static void initialize()
 174  
         {
 175  
                 // Hack for Tomcat - by saving project data right now we force loading
 176  
                 // of classes involved in this process (like ObjectOutputStream)
 177  
                 // so that it won't be necessary to load them on JVM shutdown
 178  
                 if (System.getProperty("catalina.home") != null)
 179  
                 {
 180  
                         saveGlobalProjectData();
 181  
 
 182  
                         // Force the class loader to load some classes that are
 183  
                         // required by our JVM shutdown hook.
 184  
                         // TODO: Use ClassLoader.loadClass("whatever"); instead
 185  
                         ClassData.class.toString();
 186  
                         CoverageData.class.toString();
 187  
                         CoverageDataContainer.class.toString();
 188  
                         FileLocker.class.toString();
 189  
                         HasBeenInstrumented.class.toString();
 190  
                         LineData.class.toString();
 191  
                         PackageData.class.toString();
 192  
                         SourceFileData.class.toString();
 193  
                 }
 194  
 
 195  
                 // Add a hook to save the data when the JVM exits
 196  
                 saveTimer = new SaveTimer();
 197  
                 Runtime.getRuntime().addShutdownHook(new Thread(saveTimer));
 198  
 
 199  
                 // Possibly also save the coverage data every x seconds?
 200  
                 //Timer timer = new Timer(true);
 201  
                 //timer.schedule(saveTimer, 100);
 202  
         }
 203  
 
 204  
         public static void saveGlobalProjectData()
 205  
         {
 206  
                 ProjectData projectDataToSave = globalProjectData;
 207  
 
 208  
                 /*
 209  
                  * The next statement is not necessary at the moment, because this method is only called
 210  
                  * either at the very beginning or at the very end of a test.  If the code is changed
 211  
                  * to save more frequently, then this will become important.
 212  
                  */
 213  
                 globalProjectData = new ProjectData();
 214  
 
 215  
                 /*
 216  
                  * Now sleep a bit in case there is a thread still holding a reference to the "old"
 217  
                  * globalProjectData (now referenced with projectDataToSave).  
 218  
                  * We want it to finish its updates.  I assume 2 seconds is plenty of time.
 219  
                  */
 220  
                 try
 221  
                 {
 222  
                         Thread.sleep(1000);
 223  
                 }
 224  
                 catch (InterruptedException e)
 225  
                 {
 226  
                 }
 227  
 
 228  
                 // Get a file lock
 229  
                 File dataFile = CoverageDataFileHandler.getDefaultDataFile();
 230  
                 FileLocker fileLocker = new FileLocker(dataFile);
 231  
 
 232  
                 // Read the old data, merge our current data into it, then
 233  
                 // write a new ser file.
 234  
                 if (fileLocker.lock())
 235  
                 {
 236  
                         ProjectData datafileProjectData = loadCoverageDataFromDatafile(dataFile);
 237  
                         if (datafileProjectData == null)
 238  
                         {
 239  
                                 datafileProjectData = projectDataToSave;
 240  
                         }
 241  
                         else
 242  
                         {
 243  
                                 datafileProjectData.merge(projectDataToSave);
 244  
                         }
 245  
                         CoverageDataFileHandler.saveCoverageData(datafileProjectData, dataFile);
 246  
                 }
 247  
 
 248  
                 // Release the file lock
 249  
                 fileLocker.release();
 250  
         }
 251  
 
 252  
         private static ProjectData loadCoverageDataFromDatafile(File dataFile)
 253  
         {
 254  
                 ProjectData projectData = null;
 255  
 
 256  
                 // Read projectData from the serialized file.
 257  
                 if (dataFile.isFile())
 258  
                 {
 259  
                         projectData = CoverageDataFileHandler.loadCoverageData(dataFile);
 260  
                 }
 261  
 
 262  
                 if (projectData == null)
 263  
                 {
 264  
                         // We could not read from the serialized file, so use a new object.
 265  
                         System.out.println("Cobertura: Coverage data file " + dataFile.getAbsolutePath()
 266  
                                         + " either does not exist or is not readable.  Creating a new data file.");
 267  
                 }
 268  
 
 269  
                 return projectData;
 270  
         }
 271  
 
 272  
 }