Analyzer.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
    3 * All rights reserved. This program and the accompanying materials
    4 * are made available under the terms of the Eclipse Public License v1.0
    5 * which accompanies this distribution, and is available at
    6 * http://www.eclipse.org/legal/epl-v10.html
    7 *
    8 * Contributors:
    9 *    Marc R. Hoffmann - initial API and implementation
   10 *    
   11 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.core.instr;
   14
   15import static java.lang.String.format;
   16
   17import java.io.File;
   18import java.io.FileInputStream;
   19import java.io.IOException;
   20import java.io.InputStream;
   21import java.util.StringTokenizer;
   22import java.util.zip.ZipEntry;
   23import java.util.zip.ZipInputStream;
   24
   25import org.jacoco.core.data.IClassStructureVisitor;
   26import org.jacoco.core.data.IStructureVisitor;
   27import org.objectweb.asm.ClassReader;
   28import org.objectweb.asm.ClassVisitor;
   29
   30/**
   31 * Several APIs to analyze class structures.
   32 * 
   33 * @author Marc R. Hoffmann
   34 * @version $Revision: $
   35 */
   36public class Analyzer {
   37
   38    private final IStructureVisitor structureVisitor;
   39
   40    /**
   41     * Creates a new analyzer reporting to the given output.
   42     * 
   43     * @param structureVisitor
   44     *            the output instance that will receive all structure data
   45     */
   46    public Analyzer(final IStructureVisitor structureVisitor) {
   47        this.structureVisitor = structureVisitor;
   48    }
   49
   50    /**
   51     * Creates an ASM class visitor for analysis.
   52     * 
   53     * @param classid
   54     *            id of the class calculated with {@link CRC64}
   55     * @return ASM visitor to write class definition to
   56     */
   57    public ClassVisitor createAnalyzingVisitor(final long classid) {
   58        final IClassStructureVisitor classStructure = structureVisitor
   59                .visitClassStructure(classid);
   60        return new ClassAnalyzer(classStructure);
   61    }
   62
   63    /**
   64     * Analyzes the class given as a ASM reader.
   65     * 
   66     * @param reader
   67     *            reader with class definitions
   68     */
   69    public void analyze(final ClassReader reader) {
   70        final ClassVisitor visitor = createAnalyzingVisitor(CRC64
   71                .checksum(reader.b));
   72        reader.accept(visitor, 0);
   73    }
   74
   75    /**
   76     * Analyzes the class definition from a given in-memory buffer.
   77     * 
   78     * @param buffer
   79     *            class definitions
   80     */
   81    public void analyze(final byte[] buffer) {
   82        analyze(new ClassReader(buffer));
   83    }
   84
   85    /**
   86     * Analyzes the class definition from a given input stream.
   87     * 
   88     * @param input
   89     *            stream to read class definition from
   90     * @throws IOException
   91     */
   92    public void analyze(final InputStream input) throws IOException {
   93        analyze(new ClassReader(input));
   94    }
   95
   96    /**
   97     * Analyzes the class definition contained in a given file.
   98     * 
   99     * @param file
  100     *            class file
  101     * @throws IOException
  102     */
  103    public void analyze(final File file) throws IOException {
  104        final InputStream in = new FileInputStream(file);
  105        analyze(new ClassReader(in));
  106        in.close();
  107    }
  108
  109    /**
  110     * Analyzes all class files contained in the given directory and its
  111     * children.
  112     * 
  113     * @param directory
  114     *            folder to look for class files
  115     * @throws IOException
  116     *             thrown if the given file object does not represent a readable
  117     *             directory
  118     */
  119    public void analyzeAll(final File directory) throws IOException {
  120        final File[] files = directory.listFiles();
  121        if (files == null) {
  122            throw new IOException(format("Can't read directory %s.", directory));
  123        }
  124        for (final File f : files) {
  125            if (f.isDirectory()) {
  126                analyzeAll(f);
  127                continue;
  128            }
  129            if (f.getName().endsWith(".class")) {
  130                analyze(f);
  131            }
  132        }
  133    }
  134
  135    /**
  136     * Analyzes all class files contained in a JAR file.
  137     * 
  138     * @param input
  139     *            stream to read the JAR file from
  140     * @throws IOException
  141     */
  142    public void analyzeJAR(final InputStream input) throws IOException {
  143        final ZipInputStream zip = new ZipInputStream(input);
  144        while (true) {
  145            final ZipEntry entry = zip.getNextEntry();
  146            if (entry == null) {
  147                break;
  148            }
  149            if (entry.getName().endsWith(".class")) {
  150                analyze(zip);
  151            }
  152        }
  153    }
  154
  155    /**
  156     * Analyzes all class files contained in a JAR file.
  157     * 
  158     * @param jarfile
  159     *            JAR file
  160     * @throws IOException
  161     */
  162    public void analyzeJAR(final File jarfile) throws IOException {
  163        final InputStream in = new FileInputStream(jarfile);
  164        analyzeJAR(in);
  165        in.close();
  166    }
  167
  168    /**
  169     * Analyzes all class from the given class path.
  170     * 
  171     * @param path
  172     *            path definition
  173     * @param basedir
  174     *            optional base directory, if <code>null</code> the current
  175     *            working directory is used as the base for relative path
  176     *            entries
  177     * @throws IOException
  178     */
  179    public void analyzePath(final String path, final File basedir)
  180            throws IOException {
  181        final StringTokenizer tokenizer = new StringTokenizer(path,
  182                File.pathSeparator);
  183        while (tokenizer.hasMoreTokens()) {
  184            final File entry = new File(basedir, tokenizer.nextToken());
  185            if (entry.isDirectory()) {
  186                analyzeAll(entry);
  187                continue;
  188            }
  189            if (entry.isFile() && entry.getName().endsWith(".jar")) {
  190                analyzeJAR(entry);
  191            }
  192        }
  193    }
  194
  195}