package com.avaje.ebean.enhance.ant; import java.io.File; import java.io.IOException; import java.lang.instrument.IllegalClassFormatException; import com.avaje.ebean.enhance.agent.InputStreamTransform; import com.avaje.ebean.enhance.agent.Transformer; /** * Transforms class files when they are on the file system. * <p> * Typically run as part of an ANT task rather than when Ebean is running. * </p> */ public class OfflineFileTransform { final InputStreamTransform inputStreamTransform; final String inDir; final String outDir; private TransformationListener listener; /** * Note that the inDir and outDir can be the same and typically are. That * is, we enhance the class file and replace the file with the the enhanced * version of the class. * * @param transformer * object that actually transforms the class bytes * @param classLoader * the ClassLoader used as part of the transformation * @param inDir * the root directory where the class files are located * * @param outDir * the root directory where the enhanced files are written to */ public OfflineFileTransform(Transformer transformer, ClassLoader classLoader, String inDir, String outDir) { this.inputStreamTransform = new InputStreamTransform(transformer, classLoader); inDir = trimSlash(inDir); this.inDir = inDir; this.outDir = outDir == null ? inDir : outDir; } /** Register a listener to receive event notification */ public void setListener(TransformationListener v) { this.listener = v; } private String trimSlash(String dir) { if (dir.endsWith("/")){ return dir.substring(0, dir.length()-1); } else { return dir; } } /** * Process all the comma delimited list of packages. * <p> * Package names are effectively converted into a directory on the file * system, and the class files are found and processed. * </p> */ public void process(String packageNames) { if (packageNames == null) { processPackage("", true); return; } String[] pkgs = packageNames.split(","); for (int i = 0; i < pkgs.length; i++) { String pkg = pkgs[i].trim().replace('.', '/'); boolean recurse = false; if (pkg.endsWith("**")) { recurse = true; pkg = pkg.substring(0, pkg.length() - 2); } else if (pkg.endsWith("*")) { recurse = true; pkg = pkg.substring(0, pkg.length() - 1); } pkg = trimSlash(pkg); processPackage(pkg, recurse); } } private void processPackage(String dir, boolean recurse) { inputStreamTransform.log(1, "transform> pkg: " + dir); String dirPath = inDir + "/" + dir; File d = new File(dirPath); if (!d.exists()) { String m = "File not found " + dirPath; throw new RuntimeException(m); } File[] files = d.listFiles(); File file = null; try { for (int i = 0; i < files.length; i++) { file = files[i]; if (file.isDirectory()) { if (recurse) { String subdir = dir + "/" + file.getName(); processPackage(subdir, recurse); } } else { String fileName = file.getName(); if (fileName.endsWith(".java")) { // possibly a common mistake... mixing .java and .class System.err.println("Expecting a .class file but got " + fileName + " ... ignoring"); } else if (fileName.endsWith(".class")) { transformFile(file); } } } } catch (Exception e) { String fileName = file == null ? "null" : file.getName(); String m = "Error transforming file " + fileName; throw new RuntimeException(m, e); } } private void transformFile(File file) throws IOException, IllegalClassFormatException { String className = getClassName(file); byte[] result = inputStreamTransform.transform(className, file); if (result != null) { InputStreamTransform.writeBytes(result, file); if(listener!=null) { listener.logEvent("Enhanced "+file); } } } private String getClassName(File file) { String path = file.getPath(); path = path.substring(inDir.length() + 1); path = path.substring(0, path.length() - ".class".length()); // for windows... replace the return StringReplace.replace(path,"\\", "/"); } }