1 26 27 package net.sourceforge.cobertura.instrument; 28 29 import java.io.ByteArrayOutputStream ; 30 import java.io.File ; 31 import java.io.FileInputStream ; 32 import java.io.FileNotFoundException ; 33 import java.io.FileOutputStream ; 34 import java.io.IOException ; 35 import java.io.InputStream ; 36 import java.io.OutputStream ; 37 import java.util.ArrayList ; 38 import java.util.Collection ; 39 import java.util.Iterator ; 40 import java.util.List ; 41 import java.util.Vector ; 42 import java.util.zip.ZipEntry ; 43 import java.util.zip.ZipInputStream ; 44 import java.util.zip.ZipOutputStream ; 45 46 import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler; 47 import net.sourceforge.cobertura.coveragedata.ProjectData; 48 import net.sourceforge.cobertura.util.ArchiveUtil; 49 import net.sourceforge.cobertura.util.CommandLineBuilder; 50 import net.sourceforge.cobertura.util.Header; 51 import net.sourceforge.cobertura.util.IOUtil; 52 import net.sourceforge.cobertura.util.RegexUtil; 53 54 import org.apache.log4j.Logger; 55 import org.objectweb.asm.ClassReader; 56 import org.objectweb.asm.ClassWriter; 57 58 86 public class Main 87 { 88 89 private static final Logger logger = Logger.getLogger(Main.class); 90 91 private File destinationDirectory = null; 92 93 private Collection ignoreRegexes = new Vector (); 94 95 private ClassPattern classPattern = new ClassPattern(); 96 97 private ProjectData projectData = null; 98 99 104 private static boolean isClass(ZipEntry entry) 105 { 106 return entry.getName().endsWith(".class"); 107 } 108 109 private boolean addInstrumentationToArchive(CoberturaFile file, InputStream archive, 110 OutputStream output) throws Exception 111 { 112 ZipInputStream zis = null; 113 ZipOutputStream zos = null; 114 115 try 116 { 117 zis = new ZipInputStream (archive); 118 zos = new ZipOutputStream (output); 119 return addInstrumentationToArchive(file, zis, zos); 120 } 121 finally 122 { 123 zis = (ZipInputStream )IOUtil.closeInputStream(zis); 124 zos = (ZipOutputStream )IOUtil.closeOutputStream(zos); 125 } 126 } 127 128 private boolean addInstrumentationToArchive(CoberturaFile file, ZipInputStream archive, 129 ZipOutputStream output) throws Exception 130 { 131 136 boolean modified = false; 137 ZipEntry entry; 138 while ((entry = archive.getNextEntry()) != null) 139 { 140 try 141 { 142 String entryName = entry.getName(); 143 144 150 if (ArchiveUtil.isSignatureFile(entry.getName())) 151 { 152 continue; 153 } 154 ZipEntry outputEntry = new ZipEntry (entry.getName()); 155 outputEntry.setComment(entry.getComment()); 156 outputEntry.setExtra(entry.getExtra()); 157 outputEntry.setTime(entry.getTime()); 158 output.putNextEntry(outputEntry); 159 160 byte[] entryBytes = IOUtil 162 .createByteArrayFromInputStream(archive); 163 164 if ((classPattern.isSpecified()) && ArchiveUtil.isArchive(entryName)) 166 { 167 Archive archiveObj = new Archive(file, entryBytes); 168 addInstrumentationToArchive(archiveObj); 169 if (archiveObj.isModified()) 170 { 171 modified = true; 172 entryBytes = archiveObj.getBytes(); 173 outputEntry.setTime(System.currentTimeMillis()); 174 } 175 } 176 else if (isClass(entry) && classPattern.matches(entryName)) 177 { 178 ClassReader cr = new ClassReader(entryBytes); 180 ClassWriter cw = new ClassWriter(true); 181 ClassInstrumenter cv = new ClassInstrumenter(projectData, 182 cw, ignoreRegexes); 183 cr.accept(cv, false); 184 185 if (cv.isInstrumented()) 188 { 189 logger.debug("Putting instrumented entry: " 190 + entry.getName()); 191 entryBytes = cw.toByteArray(); 192 modified = true; 193 outputEntry.setTime(System.currentTimeMillis()); 194 } 195 } 196 197 output.write(entryBytes); 199 output.closeEntry(); 200 archive.closeEntry(); 201 } 202 catch (Exception e) 203 { 204 logger.warn("Problems with archive entry: " + entry); 205 throw e; 206 } 207 output.flush(); 208 } 209 return modified; 210 } 211 212 private void addInstrumentationToArchive(Archive archive) throws Exception 213 { 214 InputStream in = null; 215 ByteArrayOutputStream out = null; 216 try 217 { 218 in = archive.getInputStream(); 219 out = new ByteArrayOutputStream (); 220 boolean modified = addInstrumentationToArchive(archive.getCoberturaFile(), in, out); 221 222 if (modified) 223 { 224 out.flush(); 225 byte[] bytes = out.toByteArray(); 226 archive.setModifiedBytes(bytes); 227 } 228 } 229 finally 230 { 231 in = IOUtil.closeInputStream(in); 232 out = (ByteArrayOutputStream )IOUtil.closeOutputStream(out); 233 } 234 } 235 236 private void addInstrumentationToArchive(CoberturaFile archive) 237 { 238 logger.debug("Instrumenting archive " + archive.getAbsolutePath()); 239 240 File outputFile = null; 241 ZipInputStream input = null; 242 ZipOutputStream output = null; 243 boolean modified = false; 244 try 245 { 246 try 248 { 249 input = new ZipInputStream (new FileInputStream (archive)); 250 } 251 catch (FileNotFoundException e) 252 { 253 logger.warn("Cannot open archive file: " 254 + archive.getAbsolutePath(), e); 255 return; 256 } 257 258 try 260 { 261 if (destinationDirectory != null) 263 { 264 outputFile = new File (destinationDirectory, archive.getPathname()); 266 } 267 else 268 { 269 outputFile = File.createTempFile( 271 "CoberturaInstrumentedArchive", "jar"); 272 outputFile.deleteOnExit(); 273 } 274 output = new ZipOutputStream (new FileOutputStream (outputFile)); 275 } 276 catch (IOException e) 277 { 278 logger.warn("Cannot open file for instrumented archive: " 279 + archive.getAbsolutePath(), e); 280 return; 281 } 282 283 try 285 { 286 modified = addInstrumentationToArchive(archive, input, output); 287 } 288 catch (Exception e) 289 { 290 logger.warn("Cannot instrument archive: " 291 + archive.getAbsolutePath(), e); 292 return; 293 } 294 } 295 finally 296 { 297 input = (ZipInputStream )IOUtil.closeInputStream(input); 298 output = (ZipOutputStream )IOUtil.closeOutputStream(output); 299 } 300 301 if (modified && (destinationDirectory == null)) 304 { 305 try 306 { 307 logger.debug("Moving " + outputFile.getAbsolutePath() + " to " 308 + archive.getAbsolutePath()); 309 IOUtil.moveFile(outputFile, archive); 310 } 311 catch (IOException e) 312 { 313 logger.warn("Cannot instrument archive: " 314 + archive.getAbsolutePath(), e); 315 return; 316 } 317 } 318 if ((destinationDirectory != null) && (!modified)) 319 { 320 outputFile.delete(); 321 } 322 } 323 324 private void addInstrumentationToSingleClass(File file) 325 { 326 logger.debug("Instrumenting class " + file.getAbsolutePath()); 327 328 InputStream inputStream = null; 329 ClassWriter cw; 330 ClassInstrumenter cv; 331 try 332 { 333 inputStream = new FileInputStream (file); 334 ClassReader cr = new ClassReader(inputStream); 335 cw = new ClassWriter(true); 336 cv = new ClassInstrumenter(projectData, cw, ignoreRegexes); 337 cr.accept(cv, false); 338 } 339 catch (Throwable t) 340 { 341 logger.warn("Unable to instrument file " + file.getAbsolutePath(), 342 t); 343 return; 344 } 345 finally 346 { 347 inputStream = IOUtil.closeInputStream(inputStream); 348 } 349 350 OutputStream outputStream = null; 351 try 352 { 353 if (cv.isInstrumented()) 354 { 355 File outputFile; 358 if (destinationDirectory == null) 359 outputFile = file; 360 else 361 outputFile = new File (destinationDirectory, cv 362 .getClassName().replace('.', File.separatorChar) 363 + ".class"); 364 365 File parentFile = outputFile.getParentFile(); 366 if (parentFile != null) 367 { 368 parentFile.mkdirs(); 369 } 370 371 byte[] instrumentedClass = cw.toByteArray(); 372 outputStream = new FileOutputStream (outputFile); 373 outputStream.write(instrumentedClass); 374 } 375 } 376 catch (Throwable t) 377 { 378 logger.warn("Unable to instrument file " + file.getAbsolutePath(), 379 t); 380 return; 381 } 382 finally 383 { 384 outputStream = IOUtil.closeOutputStream(outputStream); 385 } 386 } 387 388 private void addInstrumentation(CoberturaFile coberturaFile) 392 { 393 if (coberturaFile.isClass() && classPattern.matches(coberturaFile.getPathname())) 394 { 395 addInstrumentationToSingleClass(coberturaFile); 396 } 397 else if (coberturaFile.isDirectory()) 398 { 399 String [] contents = coberturaFile.list(); 400 for (int i = 0; i < contents.length; i++) 401 { 402 File relativeFile = new File (coberturaFile.getPathname(), contents[i]); 403 CoberturaFile relativeCoberturaFile = new CoberturaFile(coberturaFile.getBaseDir(), 404 relativeFile.toString()); 405 addInstrumentation(relativeCoberturaFile); 407 } 408 } 409 } 410 411 private void parseArguments(String [] args) 412 { 413 File dataFile = CoverageDataFileHandler.getDefaultDataFile(); 414 415 List filePaths = new ArrayList (); 417 String baseDir = null; 418 for (int i = 0; i < args.length; i++) 419 { 420 if (args[i].equals("--basedir")) 421 baseDir = args[++i]; 422 else if (args[i].equals("--datafile")) 423 dataFile = new File (args[++i]); 424 else if (args[i].equals("--destination")) 425 destinationDirectory = new File (args[++i]); 426 else if (args[i].equals("--ignore")) 427 { 428 RegexUtil.addRegex(ignoreRegexes, args[++i]); 429 } 430 else if (args[i].equals("--includeClasses")) 431 { 432 classPattern.addIncludeClassesRegex(args[++i]); 433 } 434 else if (args[i].equals("--excludeClasses")) 435 { 436 classPattern.addExcludeClassesRegex(args[++i]); 437 } 438 else 439 { 440 CoberturaFile coberturaFile = new CoberturaFile(baseDir, args[i]); 441 filePaths.add(coberturaFile); 442 } 443 } 444 445 if (dataFile.isFile()) 447 projectData = CoverageDataFileHandler.loadCoverageData(dataFile); 448 if (projectData == null) 449 projectData = new ProjectData(); 450 451 System.out.println("Instrumenting " + filePaths.size() + " " 453 + (filePaths.size() == 1 ? "file" : "files") 454 + (destinationDirectory != null ? " to " 455 + destinationDirectory.getAbsoluteFile() : "")); 456 457 Iterator iter = filePaths.iterator(); 458 while (iter.hasNext()) 459 { 460 CoberturaFile coberturaFile = (CoberturaFile)iter.next(); 461 if (coberturaFile.isArchive()) 462 { 463 addInstrumentationToArchive(coberturaFile); 464 } 465 else 466 { 467 addInstrumentation(coberturaFile); 468 } 469 } 470 471 CoverageDataFileHandler.saveCoverageData(projectData, dataFile); 473 } 474 475 public static void main(String [] args) 476 { 477 Header.print(System.out); 478 479 long startTime = System.currentTimeMillis(); 480 481 Main main = new Main(); 482 483 try { 484 args = CommandLineBuilder.preprocessCommandLineArguments( args); 485 } catch( Exception ex) { 486 System.err.println( "Error: Cannot process arguments: " + ex.getMessage()); 487 System.exit(1); 488 } 489 main.parseArguments(args); 490 491 long stopTime = System.currentTimeMillis(); 492 System.out.println("Instrument time: " + (stopTime - startTime) + "ms"); 493 } 494 495 } 496 | Popular Tags |