Coverage Report - net.sourceforge.cobertura.util.FileFinder
 
Classes in this File Line Coverage Branch Coverage Complexity
FileFinder
96%
51/53
85%
22/26
3.667
 
 1  
 /*
 2  
  * Cobertura - http://cobertura.sourceforge.net/
 3  
  *
 4  
  * Copyright (C) 2005 Jeremy Thomerson
 5  
  * Copyright (C) 2005 Grzegorz Lukasik
 6  
  *
 7  
  * Cobertura is free software; you can redistribute it and/or modify
 8  
  * it under the terms of the GNU General Public License as published
 9  
  * by the Free Software Foundation; either version 2 of the License,
 10  
  * or (at your option) any later version.
 11  
  *
 12  
  * Cobertura is distributed in the hope that it will be useful, but
 13  
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15  
  * General Public License for more details.
 16  
  *
 17  
  * You should have received a copy of the GNU General Public License
 18  
  * along with Cobertura; if not, write to the Free Software
 19  
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 20  
  * USA
 21  
  */
 22  
 package net.sourceforge.cobertura.util;
 23  
 
 24  
 import java.io.File;
 25  
 import java.io.IOException;
 26  
 import java.util.ArrayList;
 27  
 import java.util.HashMap;
 28  
 import java.util.HashSet;
 29  
 import java.util.Iterator;
 30  
 import java.util.List;
 31  
 import java.util.Map;
 32  
 import java.util.Set;
 33  
 
 34  
 import org.apache.log4j.Logger;
 35  
 
 36  
 
 37  
 /**
 38  
  * Maps source file names to existing files. After adding description
 39  
  * of places files can be found in, it can be used to localize 
 40  
  * the files. 
 41  
  * 
 42  
  * <p>
 43  
  * FileFinder supports two types of source files locations:
 44  
  * <ul>
 45  
  *     <li>source root directory, defines the directory under 
 46  
  *     which source files are located,</li>
 47  
  *     <li>pair (base directory, file path relative to base directory).</li>
 48  
  * </ul>
 49  
  * The difference between these two is that in case of the first you add all
 50  
  * source files under the specified root directory, and in the second you add
 51  
  * exactly one file. In both cases file to be found has to be located under 
 52  
  * subdirectory that maps to package definition provided with the source file name.      
 53  
  *  
 54  
  * @author Jeremy Thomerson
 55  
  */
 56  26
 public class FileFinder {
 57  
 
 58  9
         private static Logger LOGGER = Logger.getLogger(FileFinder.class);
 59  
         
 60  
         // Contains Strings with directory paths
 61  26
         private Set sourceDirectories = new HashSet();
 62  
         
 63  
         // Contains pairs (String directoryRoot, Set fileNamesRelativeToRoot)
 64  26
         private Map sourceFilesMap = new HashMap();
 65  
 
 66  
         /**
 67  
          * Adds directory that is a root of sources. A source file
 68  
          * that is under this directory will be found if relative
 69  
          * path to the file from root matches package name.
 70  
          * <p>
 71  
          * Example:
 72  
          * <pre>
 73  
          * fileFinder.addSourceDirectory( "C:/MyProject/src/main");
 74  
          * fileFinder.addSourceDirectory( "C:/MyProject/src/test");
 75  
          * </pre>
 76  
          * In path both / and \ can be used.
 77  
          * </p> 
 78  
          * 
 79  
          * @param directory The root of source files 
 80  
          * @throws NullPointerException if <code>directory</code> is <code>null</code>
 81  
          */
 82  
         public void addSourceDirectory( String directory) {
 83  36
                 if( LOGGER.isDebugEnabled())
 84  36
                         LOGGER.debug( "Adding sourceDirectory=[" + directory + "]");
 85  
 
 86  
                 // Change \ to / in case of Windows users
 87  36
                 directory = getCorrectedPath(directory);
 88  35
                 sourceDirectories.add(directory);
 89  35
         }
 90  
 
 91  
         /**
 92  
          * Adds file by specifying root directory and relative path to the
 93  
          * file in it. Adds exactly one file, relative path should match
 94  
          * package that the source file is in, otherwise it will be not
 95  
          * found later.
 96  
          * <p>
 97  
          * Example:
 98  
          * <pre>
 99  
          * fileFinder.addSourceFile( "C:/MyProject/src/main", "com/app/MyClass.java");
 100  
          * fileFinder.addSourceFile( "C:/MyProject/src/test", "com/app/MyClassTest.java");
 101  
          * </pre>
 102  
          * In paths both / and \ can be used.
 103  
          * </p>
 104  
          * 
 105  
          * @param baseDir sources root directory
 106  
          * @param file path to source file relative to <code>baseDir</code>
 107  
          * @throws NullPointerException if either <code>baseDir</code> or <code>file</code> is <code>null</code>
 108  
          */
 109  
         public void addSourceFile( String baseDir, String file) {
 110  70
                 if( LOGGER.isDebugEnabled())
 111  70
                         LOGGER.debug( "Adding sourceFile baseDir=[" + baseDir + "] file=[" + file + "]");
 112  
 
 113  70
                 if( baseDir==null || file==null)
 114  2
                         throw new NullPointerException();
 115  
         
 116  
                 // Change \ to / in case of Windows users
 117  68
                 file = getCorrectedPath( file);
 118  68
                 baseDir = getCorrectedPath( baseDir);
 119  
                 
 120  
                 // Add file to sourceFilesMap
 121  68
                 Set container = (Set) sourceFilesMap.get(baseDir);
 122  68
                 if( container==null) {
 123  34
                         container = new HashSet();
 124  34
                         sourceFilesMap.put( baseDir, container);
 125  
                 }
 126  68
                 container.add( file);
 127  68
         }
 128  
 
 129  
         /**
 130  
          * Maps source file name to existing file.
 131  
          * When mapping file name first values that were added with
 132  
          * {@link #addSourceDirectory} and later added with {@link #addSourceFile} are checked.
 133  
          * 
 134  
          * @param fileName source file to be mapped
 135  
          * @return existing file that maps to passed sourceFile 
 136  
          * @throws IOException if cannot map source file to existing file
 137  
          * @throws NullPointerException if fileName is null
 138  
          */
 139  
         public File getFileForSource(String fileName) throws IOException {
 140  
                 // Correct file name
 141  77
                 if( LOGGER.isDebugEnabled())
 142  77
                         LOGGER.debug( "Searching for file, name=[" + fileName + "]");
 143  77
                 fileName = getCorrectedPath( fileName);
 144  
 
 145  
                 // Check inside sourceDirectories
 146  76
                 for( Iterator it=sourceDirectories.iterator(); it.hasNext();) {
 147  76
                         String directory = (String)it.next();
 148  76
                         File file = new File( directory, fileName);
 149  76
                         if( file.isFile()) {
 150  24
                                 LOGGER.debug( "Found inside sourceDirectories");
 151  24
                                 return file;
 152  
                         }
 153  52
                 }
 154  
                 
 155  
                 // Check inside sourceFilesMap
 156  52
                 for( Iterator it=sourceFilesMap.keySet().iterator(); it.hasNext();) {
 157  59
                         String directory = (String)it.next();
 158  59
                         Set container = (Set) sourceFilesMap.get(directory);
 159  59
                         if( !container.contains( fileName))
 160  27
                                 continue;
 161  32
                         File file = new File( directory, fileName);
 162  32
                         if( file.isFile()) {
 163  32
                                 LOGGER.debug( "Found inside sourceFilesMap");
 164  32
                                 return file;
 165  
                         }
 166  0
                 }
 167  
 
 168  
                 // Have not found? Throw an error.
 169  20
                 LOGGER.debug( "File not found");
 170  20
                 throw new IOException( "Cannot find source file, name=["+fileName+"]");
 171  
         }
 172  
 
 173  
         /**
 174  
          * Returns a list with string for all source directories.
 175  
          * Example: <code>[C:/MyProject/src/main,C:/MyProject/src/test]</code>
 176  
          * 
 177  
          * @return list with Strings for all source roots, or empty list if no source roots were specified 
 178  
          */
 179  
         public List getSourceDirectoryList() {
 180  
                 // Get names from sourceDirectories
 181  12
                 List result = new ArrayList();
 182  12
                 for( Iterator it=sourceDirectories.iterator(); it.hasNext();) {
 183  10
                         result.add( it.next());
 184  10
                 }
 185  
                 
 186  
                 // Get names from sourceFilesMap
 187  12
                 for( Iterator it=sourceFilesMap.keySet().iterator(); it.hasNext();) {
 188  7
                         result.add(it.next());
 189  7
                 }
 190  
                 
 191  
                 // Return combined names
 192  12
                 return result;
 193  
         }
 194  
 
 195  
     private String getCorrectedPath(String path) {
 196  249
         return path.replace('\\', '/');
 197  
     }
 198  
 
 199  
     /**
 200  
      * Returns string representation of FileFinder.
 201  
      */
 202  
     public String toString() {
 203  0
             return "FileFinder, source directories: " + getSourceDirectoryList().toString();
 204  
     }
 205  
 }