package com.rc.retroweaver.ant; import com.rc.retroweaver.*; import com.rc.retroweaver.event.*; import java.io.*; import org.apache.tools.ant.*; import org.apache.tools.ant.types.*; import java.util.*; /** * An Ant task for running RetroWeaver on a set of class files. * * @author Gunnar Grim * @author Toby Reyelts * */ public class RetroWeaverTask extends Task { //////////////////////////////////////////////////////////////////////////////// // Constants and variables. /** * The destination directory for processd classes, or <code>null</code> for in place * processing. */ private File itsDestDir; /** * Indicates if an error should cause the script to fail. Default to <code>true</code>. */ private boolean itsFailOnError = true; /** * The set of files to be weaved. */ private List<FileSet> itsFileSets = new ArrayList<FileSet>(); /** * Indicates if classes should only be processed if their current version differ from the target version. Initially <code>true</code>. */ private boolean itsLazy = true; /** * Indicates if each processed class should be logged. Initially set to <code>false</code>. */ private boolean itsVerbose = false; /** * The directory to the JDK being targetted. * */ private String refClassPath; /** * The class file version number. */ private int itsVersion = 48; /** * The class file version number. */ private static final Map<String, Integer> itsVersionMap = new HashMap<String, Integer>(); /** * Initialize the version map. */ static { itsVersionMap.put( "1.2", 46 ); itsVersionMap.put( "1.3", 47 ); itsVersionMap.put( "1.4", 48 ); itsVersionMap.put( "1.5", 49 ); } //////////////////////////////////////////////////////////////////////////////// // Constructors. /** * Construct a new RetroWeaver task. * @since 4.0.1 * @changed 4.0.1 */ public RetroWeaverTask() { } //////////////////////////////////////////////////////////////////////////////// // Property accessors and mutators. /** * Set the destination directory for processed classes. Unless specified the classes * are processed in place. * @param pDir The destination directory. */ public void setDestDir( File pDir ) { if (!pDir.isDirectory()) throw new BuildException("The destination directory doesn't exist: "+pDir, getLocation()); itsDestDir = pDir; } /** * Specify if an error should cause the script to fail. Default to <code>true</code>. * * @param pFailOnError <code>true</code> to fail, <code>false</code> to keep going. */ public void setFailOnError(boolean pFailOnError) { itsFailOnError = pFailOnError; } /** * Add a set of files to be weaved. * @param pSet The fileset. */ public void addFileSet(FileSet pFileSet) { itsFileSets.add(pFileSet); } /** * Specify if classes should only be processed if their current version differ from the target version. Initially <code>true</code>. * @param pLazy <code>true</code> for lazy processing. */ public void setLazy(boolean pLazy) { itsLazy = pLazy; } /** * Set the source directory containing classes to process. This is a shortcut to * using an embedded fileset with the specified base directory and which includes * all class files. * @param pDir The directory. */ public void setSrcDir(File pDir) { FileSet fileSet = new FileSet(); fileSet.setDir(pDir); fileSet.setIncludes("**/*.class"); addFileSet(fileSet); } /** * Specify if each processed class should be logged. Initially set to <code>false</code>. * @param pVerbose <code>true</code> for verbose processing. */ public void setVerbose(boolean pVerbose) { itsVerbose = pVerbose; } /** * Set the target class file version. Initially set to "1.4". * @param pVersion The JDK version, e g "1.3". */ public void setVersion(String pVersion) { Integer v = itsVersionMap.get(pVersion); if (v == null) throw new BuildException("Unknown version: "+pVersion, getLocation()); itsVersion = v; } /** * Turns on reference verification using the specified classpath. * Retroweaver will report any references to fields/methods/classes which don't appear * on refClassPath. * */ public void setVerifyRefs( String refClassPath ) { this.refClassPath = refClassPath; } //////////////////////////////////////////////////////////////////////////////// // Operations. /** * Run the RetroWeaver task. * @throws BuildException If a build exception occurs. */ public void execute() throws BuildException { // Check arguments. if ( itsFileSets.size() == 0 ) throw new BuildException( "Either attribute 'srcdir' must be used or atleast one fileset must be embedded.", getLocation() ); // Create and configure the weaver. RetroWeaver weaver = new RetroWeaver( itsVersion ); weaver.setLazy(itsLazy); // Set up a listener if the verbose option is true. if ( itsVerbose ) { weaver.setListener(new WeaveListener() { public void weavingPath( String pPath ) { getProject().log( RetroWeaverTask.this, "Weaving "+ pPath, Project.MSG_INFO ); } }); } else { weaver.setListener(null); } // Weave the files in the filesets. Set<String> weaved = new HashSet<String>(); try { // Process each fileset. for ( FileSet fileSet : itsFileSets ) { // Create a directory scanner for the fileset. File baseDir = fileSet.getDir(getProject()); DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); // Process each file. for (String fileName : scanner.getIncludedFiles()) { // Set up the source and output paths. File file = new File(baseDir, fileName); String sourcePath = file.getCanonicalPath(); String outputPath = null; if (itsDestDir != null) outputPath = new File(itsDestDir, fileName).getCanonicalPath(); // Weave it unless already weaved. if (!weaved.contains(sourcePath)) { weaver.weave(sourcePath, outputPath); weaved.add(sourcePath); } } } } catch (Throwable ex) { if ( itsFailOnError ) throw new BuildException( ex, getLocation() ); else getProject().log( this, ex.toString(), Project.MSG_WARN ); } // Put in the code to call the verifier from here if ( refClassPath != null ) { List<String> refPath = new ArrayList<String>(); StringTokenizer st = new StringTokenizer( refClassPath, File.pathSeparator ); while ( st.hasMoreTokens() ) { refPath.add( st.nextToken() ); } RefVerifier rv = new RefVerifier( refPath, new RefVerifier.Listener() { public void verifyStarted( String msg ) { // getProject().log( RetroWeaverTask.this, msg, Project.MSG_INFO ); } public void acceptWarning( String msg ) { getProject().log( RetroWeaverTask.this, msg, Project.MSG_WARN ); } } ); // Process each fileset. for ( FileSet fileSet : itsFileSets ) { // Create a directory scanner for the fileset. File baseDir = fileSet.getDir(getProject()); DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); // Process each file. for (String fileName : scanner.getIncludedFiles()) { // Set up the source and output paths. File file = new File(baseDir, fileName); try { String sourcePath = file.getCanonicalPath(); rv.verify( sourcePath ); } catch (Throwable ex) { throw new BuildException( ex, getLocation() ); } } } } } }