View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.javaflow.ant;
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.util.jar.JarInputStream;
24  import java.util.jar.JarOutputStream;
25  import org.apache.commons.javaflow.bytecode.transformation.ResourceTransformer;
26  import org.apache.commons.javaflow.bytecode.transformation.asm.AsmClassTransformer;
27  import org.apache.commons.javaflow.bytecode.transformation.bcel.BcelClassTransformer;
28  import org.apache.commons.javaflow.utils.RewritingUtils;
29  import org.apache.tools.ant.BuildException;
30  import org.apache.tools.ant.DirectoryScanner;
31  import org.apache.tools.ant.Project;
32  import org.apache.tools.ant.types.FileSet;
33  import org.apache.tools.ant.taskdefs.MatchingTask;
34  
35  /**
36   * Ant task that enhances class files with javaflow instrumentation.
37   *
38   * @author tcurdt
39   * @author Kohsuke Kawaguchi
40   */
41  public class AntRewriteTask extends MatchingTask {
42  
43      private ResourceTransformer transformer;
44  
45      private File dstDir;
46      private File srcDir;
47  
48      /**
49       * Directory to which the transformed files will be written.
50       * This can be the same as the source directory.
51       */
52      public void setDstDir(final File pFile) {
53          dstDir = pFile;
54      }
55  
56      /**
57       * Directory from which the input files are read.
58       * This and the inherited {@link MatchingTask} forms an implicit
59       * {@link FileSet}.
60       */
61      public void setSrcDir(final File pFile) {
62          srcDir = pFile;
63          fileset.setDir(srcDir);
64      }
65  
66      /**
67       * Sets the transformer to use.
68       *
69       * <p>
70       * This option is unpublished, because in a long run we'll
71       * likely to just focus on one transformer and get rid
72       * of the other (and this option will be removed then.)
73       *
74       * @param name
75       *      either "BCEL" or "ASM". Case insensitive.
76       */
77      public void setMode(String name) {
78          name = name.toLowerCase();
79          if(name.equals("bcel"))
80              transformer = new BcelClassTransformer();
81          else
82          if(name.equals("asm"))
83              transformer = new AsmClassTransformer();
84          else
85              throw new BuildException("Unrecognized mode: "+name);
86      }
87      
88      /**
89       * Check that all required attributes have been set and nothing
90       * silly has been entered.
91       *
92       * @since Ant 1.5
93       */
94      protected void checkParameters() throws BuildException {
95          checkDir(srcDir,"srcDir");
96          checkDir(dstDir,"dstDir");
97      }
98  
99      private void checkDir(final File pDir, final String pDescription) {
100         if (pDir == null) {
101             throw new BuildException("no " + pDescription + " directory is specified", getLocation());
102         }
103         if (!pDir.exists()) {
104             throw new BuildException(pDescription + " directory \"" + pDir + "\" does not exist", getLocation());
105         }
106         if (!pDir.isDirectory()) {
107             throw new BuildException(pDescription + " directory \"" + pDir + "\" is not a directory", getLocation());
108         }
109     }
110 
111     public void execute() throws BuildException {
112         
113         final DirectoryScanner ds = fileset.getDirectoryScanner(getProject());
114         final String[] fileNames = ds.getIncludedFiles();
115 
116         // default to BCEL, since the BCEL version is more stable
117         if(transformer==null)
118             transformer = new BcelClassTransformer();
119         
120         try {
121             for (int i = 0; i < fileNames.length; i++) {
122                 final String fileName = fileNames[i];
123                 
124                 final File source = new File(srcDir, fileName);
125                 final File destination = new File(dstDir, fileName);
126                 
127                 if (!destination.getParentFile().exists()) {
128                     log("Creating dir: " + destination.getParentFile(), Project.MSG_VERBOSE);
129                     destination.getParentFile().mkdirs();
130                 }
131 
132                 if (source.lastModified() < destination.lastModified()) {
133                     log("Omitting " + source + " as " + destination + " is up to date", Project.MSG_VERBOSE);
134                     continue;
135                 }
136                 
137                 if (fileName.endsWith(".class")) {
138                     log("Rewriting " + source + " to " + destination, Project.MSG_VERBOSE);
139                     System.out.println("Rewriting " + source);
140 
141                     RewritingUtils.rewriteClassFile( source, transformer, destination );
142                 }
143 
144                 if (fileName.endsWith(".jar")
145                     || fileName.endsWith(".ear")
146                     || fileName.endsWith(".zip")
147                     || fileName.endsWith(".war")) {
148 
149                     log("Rewriting " + source + " to " + destination, Project.MSG_VERBOSE);
150 
151                     RewritingUtils.rewriteJar(
152                             new JarInputStream(new FileInputStream(source)),
153                             transformer,
154                             new JarOutputStream(new FileOutputStream(destination))
155                             );
156                     
157                 }
158             }
159         } catch (IOException e) {
160             throw new BuildException(e);
161         }
162 
163     }
164 }