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

Revision 1628, 7.7 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 org.jcoderz.commons.tracing.TracingInjector.Matcher;
36
37import java.util.Iterator;
38import java.util.logging.Level;
39import java.util.logging.Logger;
40
41import org.objectweb.asm.Opcodes;
42import org.objectweb.asm.tree.AbstractInsnNode;
43import org.objectweb.asm.tree.ClassNode;
44import org.objectweb.asm.tree.FieldInsnNode;
45import org.objectweb.asm.tree.FieldNode;
46import org.objectweb.asm.tree.InsnList;
47import org.objectweb.asm.tree.InsnNode;
48import org.objectweb.asm.tree.LabelNode;
49import org.objectweb.asm.tree.LdcInsnNode;
50import org.objectweb.asm.tree.LineNumberNode;
51import org.objectweb.asm.tree.MethodInsnNode;
52import org.objectweb.asm.tree.MethodNode;
53
54/**
55 * Takes care to add Tracing to the methods.
56 * @author mandelan
57 */
58public class ClassTracingInjector
59{
60  private static final int STATIC_BLOCK_LINE_NUMBER = 1;
61  private static final String CLASSNAME = ClassTracingInjector.class.getName();
62  private static final Logger logger = Logger.getLogger(CLASSNAME);
63  private final ClassNode mClassNode;
64  private final String mClassName;
65  private boolean mStaticLoggerInserted = false;
66  private MethodNode mStaticInit;
67  private final boolean mJava5;
68  private final boolean mPai;
69
70  /**
71   *
72   * @param cn
73   * @param java5
74   * @param pai
75   */
76  public ClassTracingInjector(ClassNode cn, boolean java5, boolean pai)
77  {
78    mPai = pai;
79    mJava5 = java5;
80    mClassNode = cn;
81    mClassName  = cn.name.replace('/', '.');
82  }
83
84  /**
85   * Injects logging to all methods that match the given matcher.
86   * @param matcher the matcher to identify methods to inject.
87   */
88  public void inject (Matcher matcher)
89  {
90    // No tracing for interfaces.
91    if ((mClassNode.access & Opcodes.ACC_INTERFACE) == 0)
92    {
93      final Iterator i = mClassNode.methods.iterator();
94      while (i.hasNext())
95      {
96        final MethodNode mn = (MethodNode) i.next();
97        if (matcher.matches(mClassNode, mn))
98        {
99          if (logger.isLoggable(Level.FINEST))
100          {
101            logger.finest("Will inject tracing into: "
102                + AsmUtil.toString(mClassNode, mn));
103          }
104          final MethodTracingInjector mi
105            = new MethodTracingInjector(mn, this);
106          mi.inject();
107        }
108        else
109        {
110          if (logger.isLoggable(Level.FINEST))
111          {
112            logger.finest("No match: "
113                + AsmUtil.toString(mClassNode, mn));
114          }
115        }
116        if ("<clinit>".equals(mn.name) && mStaticInit == null)
117        {
118          mStaticInit = mn;
119        }
120      }
121      if (!mStaticLoggerInserted)
122      {
123        MethodNode mn;
124        if (mStaticInit == null)
125        {
126          if (logger.isLoggable(Level.FINEST))
127          {
128            logger.finest("Creating new static initializer for class: "
129                + AsmUtil.toString(mClassNode));
130          }
131          mn = new MethodNode(
132            Opcodes.ACC_STATIC,  "<clinit>", "()V", null, null);
133          mn.instructions = new InsnList();
134          final LabelNode start = new LabelNode();
135          mn.instructions.add(start);
136          mn.instructions.add(new LineNumberNode(STATIC_BLOCK_LINE_NUMBER, start));
137          mn.instructions.add(new InsnNode(Opcodes.RETURN));
138          mClassNode.methods.add(mn);
139        }
140        else
141        {
142          mn = mStaticInit;
143          if (logger.isLoggable(Level.FINEST))
144          {
145            logger.finest("Using existing static initializer: "
146                + AsmUtil.toString(mClassNode, mn));
147          }
148        }
149        final InsnList cmd = new InsnList();
150        injectStaticLoggerMember(cmd);
151        // get first none label node
152        AbstractInsnNode first = mn.instructions.getFirst();
153        while (first.getNext() != null
154            && first.getType() == AbstractInsnNode.LABEL)
155        {
156          first = first.getNext();
157        }
158        mn.instructions.insertBefore(first, cmd);
159        mStaticLoggerInserted = true;
160      }
161    }
162    else
163    { // No tracing for interfaces.
164      if (logger.isLoggable(Level.FINEST))
165      {
166        logger.finest("No tracing in interfaces! "
167            + AsmUtil.toString(mClassNode));
168      }
169
170    }
171  }
172
173  public ClassNode getClassNode ()
174  {
175    return mClassNode;
176  }
177
178  public String getClassName ()
179  {
180    return mClassName;
181  }
182
183  /**
184   *
185   * @param cmd
186   */
187  public void getStaticLoggerOnStack (InsnList cmd)
188  {
189    cmd.add(new FieldInsnNode(
190        Opcodes.GETSTATIC,
191        mClassNode.name,
192        TracingInjector.STATIC_LOGGER_FIELD_NAME,
193        "Ljava/util/logging/Logger;"));
194  }
195
196  /**
197   * Load the class name reference to the stack.
198   * @param cmd the instruction list where to add the command to.
199   */
200  public void getClassNameOnStack(InsnList cmd)
201  {
202    cmd.add(new LdcInsnNode(mClassName));
203  }
204
205  /**
206   * Injects the static logger member and takes care for the
207   * static initialization.
208   * @param cmd the command list to add the code to.
209   */
210  public void injectStaticLoggerMember (InsnList cmd)
211  {
212    if (!mStaticLoggerInserted)
213    {
214      final FieldNode staticLogger
215        = new FieldNode(
216            Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL
217          + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC,
218          TracingInjector.STATIC_LOGGER_FIELD_NAME,
219          "Ljava/util/logging/Logger;",
220          null,
221          null);
222      mClassNode.fields.add(staticLogger);
223      getClassNameOnStack(cmd);
224      cmd.add(new MethodInsnNode(
225          Opcodes.INVOKESTATIC,
226          "java/util/logging/Logger",
227          "getLogger",
228          "(Ljava/lang/String;)Ljava/util/logging/Logger;"));
229      cmd.add(new FieldInsnNode(
230          Opcodes.PUTSTATIC,
231          mClassNode.name,
232          TracingInjector.STATIC_LOGGER_FIELD_NAME,
233          "Ljava/util/logging/Logger;"));
234      mStaticLoggerInserted = true;
235    }
236  }
237
238  public boolean isJava5()
239  {
240    return mJava5;
241  }
242
243  public boolean isPai()
244  {
245    return mPai;
246  }
247}
Note: See TracBrowser for help on using the browser.