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}