View Javadoc

1   /*
2    * Jour - java profiler and monitoring library
3    *
4    * Copyright (C) 2004 Jour team
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Library General Public
8    * License as published by the Free Software Foundation; either
9    * version 2 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Library General Public License for more details.
15   *
16   * You should have received a copy of the GNU Library General Public
17   * License along with this library; if not, write to the
18   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   * Boston, MA  02111-1307, USA.
20   */
21  package net.sf.jour.instrumentor;
22  
23  import org.apache.log4j.Logger;
24  
25  import javassist.CannotCompileException;
26  import javassist.*;
27  import javassist.CtConstructor;
28  import javassist.CtMethod;
29  import javassist.CtNewMethod;
30  import javassist.NotFoundException;
31  import javassist.bytecode.CodeAttribute;
32  
33  import net.sf.jour.InterceptorException;
34  import net.sf.jour.rt.agent.InstrumentationMap;
35  
36  /***
37   * TODO add docs
38   *
39   * Created on 02.12.2004
40   *
41   * Contributing Author(s):
42   *
43   *   Misha Lifschitz <mishalifschitz at users.sourceforge.net> (Inital implementation)
44   *   Vlad Skarzhevskyy <vlads at users.sourceforge.net> (Inital implementation)
45   * 
46   * @author michaellif
47   * @version $Revision: 1.12 $ ($Author: vlads $) $Date: 2004/12/13 06:19:10 $
48   */
49  
50  public class ProfilerInstrumentor extends AbstractInstrumentor implements InstrumentorConsts {
51  
52  	protected static final Logger log = Logger.getLogger(ProfilerInstrumentor.class);
53  	
54      /***
55       * DOCUMENT ME!
56       * 
57       * @param clazz
58       *            DOCUMENT ME!
59       * 
60       * @throws InterceptorException
61       *             DOCUMENT ME!
62       */
63      public boolean instrumentClass(CtClass clazz) throws InterceptorException {
64          try {
65              //TODO needs filter return addFinalize(clazz);
66              return false;
67          } catch (Exception e) {
68              e.printStackTrace();
69              throw new InterceptorException("Failed to add finalize() to class " + clazz);
70          }
71      }
72  
73      public boolean instrumentMethod(CtClass clazz, CtMethod method) throws InterceptorException {
74          return addEvents(method);
75      }
76  
77      public boolean instrumentConstructor(CtClass clazz, CtConstructor constructor)
78              throws InterceptorException {
79          //TODO needs filter return addEvents(constructor);
80          return false;
81      }
82      
83      public String getMapedEventID(CtBehavior behavior, long id) {
84          StringBuffer code = new StringBuffer();
85          code.append("\n new net.sf.jour.rt.agent.MapedEventID((long)");
86          code.append(id);
87  		code.append(")");
88  		return code.toString();
89      }
90  
91      private boolean addEvents(CtBehavior behavior) throws InterceptorException {
92          try {
93              CodeAttribute ca = behavior.getMethodInfo().getCodeAttribute();
94              if (ca == null) {
95                  return false;
96              }
97              if (log.isDebugEnabled()) {
98                  log.debug("instrument " + behavior.getDeclaringClass().getName() + "->" + behavior.getName() + behavior.getSignature());
99              }
100             /*
101             this adds the code like this:
102             
103              import net.sf.jour.rt.agent.Elog;
104              import net.sf.jour.rt.agent.ProfilerEvent
105              
106              if (Elog.ON) {
107                Elog.logEvent(new ProfilerEvent(ProfilerEvent.START,
108                                                new MapedEventID(1),
109                                                null);
110              }
111              
112              ...original code.
113              
114              if (Elog.ON) {
115                Elog.logEvent(new ProfilerEvent(ProfilerEvent.END,
116                                                new MapedEventID(1),
117                                                null);
118              }
119              
120             */
121             // In case of problems this could be used for debug
122             final boolean useEmptyEvent = false;
123             // No point in this You'l get calls not found anyway
124             final boolean useTry = false;
125 
126 			StringBuffer commonCode = new StringBuffer();
127 			if (useTry) {
128 			    commonCode.append("try {");
129 			}
130 			commonCode.append("\nif (net.sf.jour.rt.agent.Elog.ON) {\n");
131 			commonCode.append("net.sf.jour.rt.agent.Elog.logEvent(");
132 			if (useEmptyEvent) {
133 				commonCode.append(" new net.sf.jour.rt.agent.EmptyEvent(");
134 			} else { 
135 				commonCode.append(" new net.sf.jour.rt.agent.ProfilerEvent(\n");
136 				commonCode.append("  net.sf.jour.rt.agent.ProfilerEvent.");
137         	}
138 
139 
140 			long id = InstrumentationMap.instance().getID(behavior.getDeclaringClass().getName(), behavior.getName(), behavior.getSignature());
141 			            
142 			StringBuffer commonCodeEnd = new StringBuffer();
143 			if (!useEmptyEvent) {
144 				commonCodeEnd.append(getMapedEventID(behavior, id));
145 			}
146 			commonCodeEnd.append("));\n}");
147 			if (useTry) {
148 			    commonCodeEnd.append("} catch(Throwable t) {};");
149 			}
150             
151 			StringBuffer codeBefore = new StringBuffer();
152 			StringBuffer codeAfter = new StringBuffer();
153 			StringBuffer codeCatch = new StringBuffer();
154 
155 			codeBefore.append(commonCode.toString());
156 			if (!useEmptyEvent) {
157 				codeBefore.append("START, null, ");
158 			}
159 			codeBefore.append(commonCodeEnd.toString());
160 			
161 			codeAfter.append(commonCode.toString());
162 			if (!useEmptyEvent) {
163 				codeAfter.append("END, null, ");
164 			}
165 			codeAfter.append(commonCodeEnd.toString());
166 			
167 			codeCatch.append(commonCode.toString());
168 			if (!useEmptyEvent) {
169 				codeCatch.append("END, $e,");
170 			}
171 			codeCatch.append(commonCodeEnd.toString());
172 			codeCatch.append("throw $e;\n");
173 						
174             try {
175                 behavior.insertBefore(codeBefore.toString());
176             } catch (Exception be) {
177                 log.debug(codeBefore);
178                 throw be;
179             } catch (Error be) {
180                 log.debug(codeBefore);
181                 throw be;
182             }
183 
184             try {
185                 behavior.insertAfter(codeAfter.toString());
186             } catch (Exception be) {
187                 log.debug(codeAfter);
188                 throw be;                
189             } catch (Error ae) {
190                 log.debug(codeAfter);
191                 throw ae;
192             }
193 
194             try {
195                 behavior.addCatch(codeCatch.toString(), ClassPool.getDefault().get("java.lang.Throwable"));
196             } catch (Error ce) {
197                 log.debug(codeCatch);
198                 throw ce;
199             }                
200             
201             return true;
202             
203 		} catch (Error e) {
204 			log.error("Profiler error", e);
205 			throw e;
206         } catch (Exception e) {
207         	log.error("Profiler error", e);
208             throw new InterceptorException("Failed to add profiler events to " + behavior.getName());
209         }
210     }
211 
212     private boolean addFinalize(CtClass clazz) throws CannotCompileException, NotFoundException {
213         CtMethod finalize;
214         CtMethod[] mArray = clazz.getDeclaredMethods();
215         for (int i = 0; i < mArray.length; i++) {
216             if (mArray[i].getName().equals("finalize")
217                     && (mArray[i].getParameterTypes().length == 0)) {
218                 return false;
219             }
220         }
221         StringBuffer code = new StringBuffer();
222         code.append("protected void finalize() throws Throwable { super.finalize(); }");
223         finalize = CtNewMethod.make(code.toString(), clazz);
224         clazz.addMethod(finalize);
225         return true;
226     }
227 
228 }