root/trunk/src/java/org/jcoderz/commons/tracing/TracingInjectorTask.java

Revision 1628, 10.2 kB (checked in by amandel, 2 years ago)

Add work in progress tracing components.
- Extended TracingProxy? that allows different Traces to be used
- TracingInjector? that allows aspect like injection of the tracing aspect.

Please note that this is still work in progress.

  • Property svn:mime-type set to text/plain
Line 
1/*
2 * $Id: ArraysUtil.java 1011 2008-06-16 17:57:36Z amandel $
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.tracing;
34
35import java.io.File;
36import java.io.IOException;
37import java.util.ArrayList;
38import java.util.Iterator;
39import java.util.LinkedList;
40import java.util.List;
41import java.util.logging.Handler;
42import java.util.logging.Level;
43import java.util.logging.Logger;
44
45import org.apache.tools.ant.BuildException;
46import org.apache.tools.ant.DirectoryScanner;
47import org.apache.tools.ant.Project;
48import org.apache.tools.ant.Task;
49import org.apache.tools.ant.types.FileSet;
50import org.jcoderz.commons.tracing.TracingInjector.Matcher;
51import org.jcoderz.commons.tracing.TracingInjector.MethodMatcher;
52import org.jcoderz.commons.util.IoUtil;
53
54/**
55 * Ant task for TracingInjection.
56 *
57 * <p>This ant task takes a fileset <code>fileset</code> as input and
58 * one directory <code>destDir</code> as output. It copies ALL files
59 * from the input to the output, if the do not exist at the destination
60 * OR if the file last modified date of the source is newer than the
61 * target. Needed directories are created as used.</p>
62 *
63 * <p>As a 'side effect' all class files (*.class) that match
64 * one of the patterns given in the <code>patternFile</code> get
65 * JDK14 tracing logging (entering/exiting/throwing) injected in
66 * all methods that match the given pattern.</p>
67 *
68 * <p>If you set <code>java5</code> to <code>true</code> the
69 * generated code uses the much more efficient factory methods
70 * to box native types that had been introduced with java5
71 * (<code>new Integer(int i)</code> vs.
72 * <code>Integer.valueOf(int i)</code>). Nevertheless this only affects
73 * the code that is guarded with an <code>isLoggable(..)</code> so there no
74 * runtime penalty in the generated code if logging is disabled.</p>
75 *
76 * <p>The <code>patternFile</code> is read line by line and each line
77 * is expected to be either empty, start with a '#' or '//' or hold a
78 * valid aspectJ like pattern as defined in the
79 * AspectPattern according to <a href="http://aspectwerkz.codehaus.org/definition_issues.html">
80 *    aspectwerkz</a>. Call the target with '-v' to see
81 * the regular expression that is generated out of the input pattern.</p>
82 *
83 * <p>The task supports a <code>verbose</code> attribute. If set to true
84 * a detailed log will be generated about what is going on. This is done
85 * by increasing the JDK logging loglevel - be aware of possible
86 * side effects.</p>
87 *
88 * The following code fragment defines the
89 * <code>tracing-injector</code> ant task.<pre>
90 *   &lt;taskdef name="tracing-injector"
91 *       classname="org.jcoderz.commons.tracing.TracingInjectorTask"
92 *       classpath="lib/tracing-injector-0.1.jar"/>
93 * </pre>
94 *
95 * A valid usage sample is:<pre>
96 *   &lt;tracing-injector destDir="build/classes-log"
97 *       patternFile="config/tracing"
98 *       java5="false" verbose="false">
99 *       &lt;fileset dir="build/classes"/>
100 *     &lt;/tracing-injector>
101 * </pre>
102 *
103 * TODO: Support different Tracers to be set.
104 *
105 * @author Andreas Mandel
106 */
107public class TracingInjectorTask extends Task
108{
109//  * <pre>
110//  * TODO: Refine Documentation
111//  * TODO: Implement validate method
112//  * TODO: Add dependency checker (AsM lib)
113//  * TODO: If required allow JAR as input and/or output
114//  * </pre>
115//  *
116  private final List mSrcFiles = new ArrayList();
117  private String mDestDirName;
118  private File mDestDir;
119  private final List mSourceFiles = new LinkedList();
120  private File mPatternFile;
121  private Matcher mMatcher;
122  private boolean mJava5 = false;
123  private boolean mPai = false;
124  private boolean mVerbose = false;
125
126  /**
127   *
128   * @param fileset files to be collected.
129   */
130  public void addFileset(FileSet fileset)
131  {
132    mSrcFiles.add(fileset);
133  }
134
135  public void setDestDir(String destDir)
136  {
137    mDestDirName = destDir;
138  }
139
140  public void setPatternFile(File patternFile)
141  {
142    mPatternFile = patternFile;
143  }
144
145  public void setJava5(boolean java5)
146  {
147    mJava5 = java5;
148  }
149
150  public void setPai(boolean pai)
151  {
152    mPai = pai;
153  }
154
155  public void setVerbose(boolean verbose)
156  {
157    mVerbose = verbose;
158  }
159
160  /**
161   *
162   */
163  public void execute()
164  {
165    validate();
166
167    // BUILD MATCHER Object...
168    try
169    {
170      mMatcher = new MethodMatcher(mPatternFile);
171      // IF loglevel??
172      log("Read matcher from " + mPatternFile, Project.MSG_VERBOSE);
173      log(String.valueOf(mMatcher), Project.MSG_VERBOSE);
174    }
175    catch (IOException ex)
176    {
177      throw new BuildException("Could not build matcher from file.", ex);
178    }
179
180    for (final Iterator itFSets = mSrcFiles.iterator(); itFSets.hasNext();)
181    {
182      final FileSet fs = (FileSet) itFSets.next();
183      final DirectoryScanner ds = fs.getDirectoryScanner(getProject());
184      final File base  = ds.getBasedir();
185      final String[] includedFiles = ds.getIncludedFiles();
186      for (int i = 0; i < includedFiles.length; i++)
187      {
188        mSourceFiles.add(new SourceFile(
189            new File(base, includedFiles[i]), includedFiles[i]));
190      }
191    }
192    try
193    {
194      inject();
195    }
196    catch (IOException ex)
197    {
198      throw new BuildException(ex);
199    }
200  }
201
202  /**
203   *
204   * @throws IOException
205   */
206  public void inject()
207    throws IOException
208  {
209    while (!mSourceFiles.isEmpty())
210    {
211      final SourceFile mySource = (SourceFile) mSourceFiles.remove(0);
212
213      final File targetFile = getTargetForSource(mySource);
214
215      if (!targetFile.exists()
216          || mySource.getAbsoluteFile().lastModified()
217            > targetFile.lastModified())
218      {
219        ensurePath(targetFile);
220        if (mySource.getRelativeFileName().endsWith(".class"))
221        {
222          try
223          {
224            log("About to work on " + mySource.getAbsoluteFile()
225                + ".", Project.MSG_VERBOSE);
226            TracingInjector.inject(mySource.getAbsoluteFile(), targetFile,
227                mMatcher, mJava5, mPai);
228          }
229          catch (RuntimeException ex)
230          {
231            log("Failed with " + mySource.mAbsoluteFile + " got "
232                + ex, Project.MSG_DEBUG);
233            if (ex.getMessage() != null
234                && ex.getMessage().startsWith("JSR/RET are not supported "))
235            {
236              IoUtil.copy(mySource.getAbsoluteFile(), targetFile);
237            }
238            else
239            {
240              // THIS IS ANT 1.7.0 :-(
241              log("About to only copy " + mySource.getAbsoluteFile()
242                  + " cause " + ex + ".", ex, Project.MSG_ERR);
243              IoUtil.copy(mySource.getAbsoluteFile(), targetFile);
244            }
245          }
246        }
247        else
248        {
249          log("About to copy " + mySource.getAbsoluteFile()
250              + ".", Project.MSG_VERBOSE);
251          IoUtil.copy(mySource.getAbsoluteFile(), targetFile);
252        }
253      }
254    }
255  }
256
257  /**
258   *
259   * @param file
260   * @throws IOException
261   */
262  private void ensurePath(File file)
263    throws IOException
264  {
265    if (!file.exists())
266    {
267      if (!file.getParentFile().exists())
268      {
269        if (!file.getParentFile().mkdirs())
270        {
271          throw new IOException("Could not create dir for target files.");
272        }
273      }
274    }
275  }
276
277  /**
278   *
279   * @param mySource
280   * @return
281   */
282  private File getTargetForSource(SourceFile mySource)
283  {
284    return new File(mDestDir, mySource.getRelativeFileName());
285  }
286
287  /**
288   *
289   */
290  private void validate()
291  {
292    mDestDir = new File(mDestDirName);
293    if (mVerbose)
294    {
295      Logger.getLogger(
296          TracingInjectorTask.class.getPackage().getName()).setLevel(Level.FINEST);
297      final Handler[] handlers = Logger.getLogger("").getHandlers();
298      final int amountOfHandlers = handlers.length;
299      for (int i = 0; i < amountOfHandlers; i++)
300      {
301         try
302         {
303            handlers[i].setLevel(Level.FINEST);
304         }
305         catch (Exception ex)
306         {
307            //ignore
308         }
309      }
310    }
311  }
312
313  /**
314   *
315   * @author Andreas Mandel
316   */
317  private static class SourceFile
318  {
319    private final File mAbsoluteFile;
320    private final String mRelativeFileName;
321
322    /**
323     *
324     * @param absoluteFile
325     * @param relativeFileName
326     */
327    public SourceFile(File absoluteFile, String relativeFileName)
328    {
329      mAbsoluteFile = absoluteFile;
330      mRelativeFileName = relativeFileName;
331    }
332
333    public File getAbsoluteFile()
334    {
335      return mAbsoluteFile;
336    }
337
338    public String getRelativeFileName()
339    {
340      return mRelativeFileName;
341    }
342  }
343}
Note: See TracBrowser for help on using the browser.