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

Revision 1628, 7.6 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
35
36import java.io.File;
37import java.io.FileInputStream;
38import java.io.FileOutputStream;
39import java.io.FileReader;
40import java.io.IOException;
41import java.io.LineNumberReader;
42import java.util.ArrayList;
43import java.util.Iterator;
44import java.util.List;
45import java.util.logging.Level;
46import java.util.logging.Logger;
47
48import org.jcoderz.commons.util.FileUtils;
49import org.jcoderz.commons.util.IoUtil;
50import org.jcoderz.commons.util.StringUtil;
51import org.objectweb.asm.ClassReader;
52import org.objectweb.asm.ClassWriter;
53import org.objectweb.asm.Type;
54import org.objectweb.asm.tree.ClassNode;
55import org.objectweb.asm.tree.MethodNode;
56
57/**
58 *
59 * TODO: Create unit tests!
60 * TODO: Might add 'this' to <init> exiting logger
61 * TODO: Store {@link System#currentTimeMillis()} / nanos
62 *  to compute time!
63 * TODO: Create a method compressing the localVariableTable
64 *       + create localVariableTable if none is given! (seen with
65 *       aspectj generated classes)
66 * TODO: Instead of boolean indicating if loggable store
67 *       reference to logger or null in method variable
68 *
69 * @author mandelan
70 */
71public class TracingInjector
72{
73  static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
74  static final String PREFIX = "LGI$";
75  static final String LOCAL_PREFIX = "lgi$";
76  static final String STATIC_LOGGER_FIELD_NAME
77    = PREFIX + "LGR";
78  static final String IS_LOGGABLE_FIELD_NAME
79    = LOCAL_PREFIX + "isLoggable";
80  static final String RESULT_VAR_FIELD_NAME
81    = LOCAL_PREFIX + "result";
82
83  private static final String CLASSNAME = TracingInjector.class.getName();
84  private static final Logger logger = Logger.getLogger(CLASSNAME);
85
86  /**
87   *
88   * @author Andreas Mandel
89   */
90  public interface Matcher
91  {
92    /**
93     *
94     * @param cn
95     * @return
96     */
97    public boolean matches (ClassNode cn);
98
99    /**
100     *
101     * @param mn
102     * @return
103     */
104    public boolean matches (MethodNode mn);
105
106    /**
107     *
108     * @param cn
109     * @param mn
110     * @return
111     */
112    public boolean matches (ClassNode cn, MethodNode mn);
113  }
114
115  /**
116   *
117   * @author Andreas Mandel
118   */
119  public static class MethodMatcher implements Matcher
120  {
121    public final static String COMMENT = "#";
122    public final static String COMMENT2 = "//";
123    final List mPatterString = new ArrayList();
124    final List mPatterns = new ArrayList();
125
126    /**
127     * Method matcher that is configured by the given File.
128     *
129     * @param inFile
130     * @throws IOException
131     */
132    public MethodMatcher (File inFile)
133      throws IOException
134    {
135      LineNumberReader reader = null;
136      final FileReader fr = new FileReader(inFile);
137      try
138      {
139        reader = new LineNumberReader(fr);
140        String line = reader.readLine();
141        while (line != null)
142        {
143          if (!StringUtil.isEmptyOrNull(line) && !line.startsWith(COMMENT)
144              && !line.startsWith(COMMENT2))
145          {
146            mPatterString.add(line.trim());
147            final AspectPattern aspectPattern = new AspectPattern(line.trim());
148            mPatterns.add(aspectPattern);
149          }
150          line = reader.readLine();
151        }
152      }
153      finally
154      {
155        IoUtil.close(reader);
156        IoUtil.close(fr);
157      }
158    }
159
160    /** {@inheritDoc} */
161    public String toString ()
162    {
163      return mPatterns.toString();
164    }
165
166    /**
167     * @param cn
168     * @return
169     */
170    public boolean matches(ClassNode cn)
171    {
172      final Iterator i = mPatterns.iterator();
173      boolean matched = false;
174      while (i.hasNext() && !matched)
175      {
176        final AspectPattern pattern = (AspectPattern) i.next();
177        matched |= pattern.matchClass(cn.name);
178        // TODO: Check inheritance!!!
179        // return matcher!!!
180      }
181      return matched;
182    }
183
184    /**
185     * @param mn
186     * @return
187     */
188    public boolean matches(MethodNode mn)
189    {
190      throw new UnsupportedOperationException("TODO");
191    }
192
193    /**
194     * @param cn
195     * @param mn
196     * @return
197     */
198    public boolean matches(ClassNode cn, MethodNode mn)
199    {
200      final Iterator i = mPatterns.iterator();
201      boolean matched = false;
202      while (i.hasNext() && !matched)
203      {
204        final AspectPattern pattern = (AspectPattern) i.next();
205        if (pattern.matchClass(cn.name))
206          // TODO: Check inheritance!!!
207        {
208          matched |=
209            pattern.matchAccess(mn.access)
210            && pattern.matchMethod(mn.desc);
211        }
212      }
213      return matched;
214    }
215  }
216
217  /**
218   *
219   * @param inFile
220   * @param outFile
221   * @param matcher
222   * @param java5
223   * @param pai
224   * @throws IOException
225   */
226  public static void inject (File inFile, File outFile, Matcher matcher,
227      boolean java5, boolean pai)
228    throws IOException
229  {
230    final ClassNode cn = new ClassNode();
231    final FileInputStream is = new FileInputStream(inFile);
232    try
233    {
234      final ClassReader cr = new ClassReader(is);
235      cr.accept(cn, 0);
236    }
237    finally
238    {
239      IoUtil.close(is);
240    }
241    if (matcher.matches(cn))
242    {
243      if (logger.isLoggable(Level.FINE))
244      {
245        logger.fine("Will inject tracing into: " + cn.name);
246      }
247      new ClassTracingInjector(cn, java5, pai).inject(matcher);
248      final FileOutputStream os = new FileOutputStream(outFile);
249      try
250      {
251        final ClassWriter cw = new ClassWriter(
252            /* ClassWriter.COMPUTE_FRAMES +*/ ClassWriter.COMPUTE_MAXS);
253        cn.accept(cw);
254        os.write(cw.toByteArray());
255      }
256      finally
257      {
258        IoUtil.close(os);
259      }
260    }
261    else
262    {
263      if (logger.isLoggable(Level.FINE))
264      {
265        logger.fine("Direct copy for: " + cn.name + " (no match)");
266      }
267      FileUtils.copy(inFile, outFile);
268    }
269  }
270}
Note: See TracBrowser for help on using the browser.