alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Cobertura example source code file (FileFinder.java)

This example Cobertura source code file (FileFinder.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Cobertura tags/keywords

adding, file, file, hashset, io, ioexception, iterator, iterator, jar, jarfile, list, set, set, source, string, string, util

The Cobertura FileFinder.java source code

/*
 * Cobertura - http://cobertura.sourceforge.net/
 *
 * Copyright (C) 2005 Jeremy Thomerson
 * Copyright (C) 2005 Grzegorz Lukasik
 * Copyright (C) 2009 Charlie Squires
 * Copyright (C) 2009 John Lewis
 *
 * Cobertura is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * Cobertura is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Cobertura; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */
package net.sourceforge.cobertura.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.log4j.Logger;


/**
 * Maps source file names to existing files. After adding description
 * of places files can be found in, it can be used to localize 
 * the files. 
 * 
 * <p>
 * FileFinder supports two types of source files locations:
 * <ul>
 *     <li>source root directory, defines the directory under 
 *     which source files are located,</li>
 *     <li>pair (base directory, file path relative to base directory).
 * </ul>
 * The difference between these two is that in case of the first you add all
 * source files under the specified root directory, and in the second you add
 * exactly one file. In both cases file to be found has to be located under 
 * subdirectory that maps to package definition provided with the source file name.      
 *  
 * @author Jeremy Thomerson
 */
public class FileFinder {

	private static Logger LOGGER = Logger.getLogger(FileFinder.class);
	
	// Contains Strings with directory paths
	private Set sourceDirectories = new HashSet();
	
	// Contains pairs (String directoryRoot, Set fileNamesRelativeToRoot)
	private Map sourceFilesMap = new HashMap();

	/**
	 * Adds directory that is a root of sources. A source file
	 * that is under this directory will be found if relative
	 * path to the file from root matches package name.
	 * <p>
	 * Example:
	 * <pre>
	 * fileFinder.addSourceDirectory( "C:/MyProject/src/main");
	 * fileFinder.addSourceDirectory( "C:/MyProject/src/test");
	 * </pre>
	 * In path both / and \ can be used.
	 * </p> 
	 * 
	 * @param directory The root of source files 
	 * @throws NullPointerException if <code>directory is null
	 */
	public void addSourceDirectory( String directory) {
		if( LOGGER.isDebugEnabled())
			LOGGER.debug( "Adding sourceDirectory=[" + directory + "]");

		// Change \ to / in case of Windows users
		directory = getCorrectedPath(directory);
		sourceDirectories.add(directory);
	}

	/**
	 * Adds file by specifying root directory and relative path to the
	 * file in it. Adds exactly one file, relative path should match
	 * package that the source file is in, otherwise it will be not
	 * found later.
	 * <p>
	 * Example:
	 * <pre>
	 * fileFinder.addSourceFile( "C:/MyProject/src/main", "com/app/MyClass.java");
	 * fileFinder.addSourceFile( "C:/MyProject/src/test", "com/app/MyClassTest.java");
	 * </pre>
	 * In paths both / and \ can be used.
	 * </p>
	 * 
	 * @param baseDir sources root directory
	 * @param file path to source file relative to <code>baseDir
	 * @throws NullPointerException if either <code>baseDir or file is null
	 */
	public void addSourceFile( String baseDir, String file) {
		if( LOGGER.isDebugEnabled())
			LOGGER.debug( "Adding sourceFile baseDir=[" + baseDir + "] file=[" + file + "]");

		if( baseDir==null || file==null)
			throw new NullPointerException();
	
		// Change \ to / in case of Windows users
		file = getCorrectedPath( file);
		baseDir = getCorrectedPath( baseDir);
		
		// Add file to sourceFilesMap
		Set container = (Set) sourceFilesMap.get(baseDir);
		if( container==null) {
			container = new HashSet();
			sourceFilesMap.put( baseDir, container);
		}
		container.add( file);
	}

	/**
	 * Maps source file name to existing file.
	 * When mapping file name first values that were added with
	 * {@link #addSourceDirectory} and later added with {@link #addSourceFile} are checked.
	 * 
	 * @param fileName source file to be mapped
	 * @return existing file that maps to passed sourceFile 
	 * @throws IOException if cannot map source file to existing file
	 * @throws NullPointerException if fileName is null
	 */
	public File getFileForSource(String fileName) throws IOException {
		// Correct file name
		if( LOGGER.isDebugEnabled())
			LOGGER.debug( "Searching for file, name=[" + fileName + "]");
		fileName = getCorrectedPath( fileName);

		// Check inside sourceDirectories
		for( Iterator it=sourceDirectories.iterator(); it.hasNext();) {
			String directory = (String)it.next();
			File file = new File( directory, fileName);
			if( file.isFile()) {
				LOGGER.debug( "Found inside sourceDirectories");
				return file;
			}
		}
		
		// Check inside sourceFilesMap
		for( Iterator it=sourceFilesMap.keySet().iterator(); it.hasNext();) {
			String directory = (String)it.next();
			Set container = (Set) sourceFilesMap.get(directory);
			if( !container.contains( fileName))
				continue;
			File file = new File( directory, fileName);
			if( file.isFile()) {
				LOGGER.debug( "Found inside sourceFilesMap");
				return file;
			}
		}

		// Have not found? Throw an error.
		LOGGER.debug( "File not found");
		throw new IOException( "Cannot find source file, name=["+fileName+"]");
	}
	
	/**
	 * Maps source file name to existing file or source archive.
	 * When mapping file name first values that were added with
	 * {@link #addSourceDirectory} and later added with {@link #addSourceFile} are checked.
	 * 
	 * @param fileName source file to be mapped
	 * @return Source that maps to passed sourceFile or null if it can't be found
	 * @throws NullPointerException if fileName is null
	 */
	public Source getSource(String fileName) {
		File file = null;
		try
		{
			file = getFileForSource(fileName);
			return new Source(new FileInputStream(file), file);
		}
		catch (IOException e)
		{
			//Source file wasn't found. Try searching archives.
			return searchJarsForSource(fileName);
		}
		
	}

	/**
	 * Gets a BufferedReader for a file within a jar.
	 * 
	 * @param fileName source file to get an input stream for
	 * @return Source for existing file inside a jar that maps to passed sourceFile 
	 * or null if cannot map source file to existing file
	 */
	private Source searchJarsForSource(String fileName) {
		//Check inside jars in sourceDirectories
		for( Iterator it=sourceDirectories.iterator(); it.hasNext();) {
			String directory = (String)it.next();
			File file = new File(directory);
			//Get a list of jars and zips in the directory
			String[] jars = file.list(new JarZipFilter());
			if(jars != null) {
				for(String jar : jars) {
					try
					{
						LOGGER.debug("Looking for: " + fileName + " in "+ jar);
						JarFile jf = new JarFile(directory + "/" + jar);
	
						//Get a list of files in the jar
						Enumeration<JarEntry> files = jf.entries();
						//See if the jar has the class we need
						while(files.hasMoreElements()) {
							JarEntry entry = files.nextElement();
							if(entry.getName().equals(fileName)) {
								return new Source(jf.getInputStream(entry), jf);
							}
						}
					}
					catch (Throwable t)
					{
						LOGGER.warn("Error while reading " + jar, t);
					}
				}
			}
		}
		return null;
	}

	/**
	 * Returns a list with string for all source directories.
	 * Example: <code>[C:/MyProject/src/main,C:/MyProject/src/test]
	 * 
	 * @return list with Strings for all source roots, or empty list if no source roots were specified 
	 */
	public List getSourceDirectoryList() {
		// Get names from sourceDirectories
		List result = new ArrayList();
		for( Iterator it=sourceDirectories.iterator(); it.hasNext();) {
			result.add( it.next());
		}
		
		// Get names from sourceFilesMap
		for( Iterator it=sourceFilesMap.keySet().iterator(); it.hasNext();) {
			result.add(it.next());
		}
		
		// Return combined names
		return result;
	}

    private String getCorrectedPath(String path) {
        return path.replace('\\', '/');
    }

    /**
     * Returns string representation of FileFinder.
     */
    public String toString() {
    	return "FileFinder, source directories: " + getSourceDirectoryList().toString();
    }
    
    /**
     * A filter that accepts files that end in .jar or .zip
     */
    private class JarZipFilter implements FilenameFilter {
		public boolean accept(File dir, String name) {
			return(name.endsWith(".jar") || name.endsWith(".zip"));
		}
    }
}

Other Cobertura examples (source code examples)

Here is a short list of links related to this Cobertura FileFinder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.