View Javadoc
1   /*
2    * Copyright 2005 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package net.sf.sensor.support.spring;
18  
19  import java.util.Iterator;
20  import java.util.Set;
21  
22  import org.aopalliance.intercept.MethodInterceptor;
23  import org.aopalliance.intercept.MethodInvocation;
24  
25  import org.springframework.util.ClassUtils;
26  import org.springframework.util.StringUtils;
27  
28  import net.sf.sensor.timer.Timer;
29  import net.sf.sensor.timer.TimerRuntime;
30  
31  /***
32   * Spring method interceptor that wraps a method call in a Sensor Timer
33   * using the dependency injected {@link TimerRuntime}.
34   * <p>
35   * Method signature util methods copied from the extended JamonIntercepter
36   * as blogged by Gerald Loeffler.
37   * 
38   * @author Age Mooy 
39   */
40  public class MethodTimingInterceptor implements MethodInterceptor {
41  
42    /*** The {@link TimerRuntime} we use to access timers. */
43    private TimerRuntime timerRuntime = null;
44    
45    /*** The set of labels to associate with the {@link Timer Timers}. */
46    private Set associatedLabels = null;
47    
48    /***
49     * Property that controls whether the generated {@link Timer} label
50     * will contain the method parameter types or not. Defaults to true.
51     */
52    private boolean useParamTypesInId = true;
53    
54    
55    // ==========================================================================
56    // Interface implementation
57    // ==========================================================================
58    
59    /***
60     * Wraps the intercepted method call in a Timer using the method signature
61     * as the Timer label. If there is no {@link TimerRuntime} available, this
62     * method proceeds with the intercepted method without doing anything else.
63     * 
64     * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
65     */
66    public Object invoke(MethodInvocation mi) throws Throwable {
67      Timer timer = null;
68      
69      if (timerRuntime != null) {
70        timer = timerRuntime.getTimer(methodSignature(mi));
71        
72        if (associatedLabels != null) {
73          for (Iterator i = associatedLabels.iterator(); i.hasNext();) {
74            Object label = i.next();
75            
76            if (label instanceof String) {
77              timer.addLabel((String) label);
78            }
79          }
80        }
81        
82        timer.start();
83      }
84      
85      try {
86        return mi.proceed();
87      } finally {
88        if (timerRuntime != null) {
89          timer.stop();
90        }      
91      }
92    }
93    
94    
95    // ==========================================================================
96    // Dependency Injection
97    // ==========================================================================
98    
99    /***
100    * Sets the timerRuntime.
101    * @param timerRuntime The timerRuntime to set.
102    */
103   public void setTimerRuntime(TimerRuntime timerRuntime) {
104     this.timerRuntime = timerRuntime;
105   }
106   
107   /***
108    * Sets the associatedLabels.
109    * @param associatedLabels The associatedLabels to set.
110    */
111   public void setAssociatedLabels(Set associatedLabels) {
112     this.associatedLabels = associatedLabels;
113   }
114   
115   /***
116    * Sets the property that controls whether the generated {@link Timer}
117    * label will contain the method parameter types or not. Defaults to true.
118    * @param useParamTypesInId The useParamTypesInId to set.
119    */
120   public void setUseParamTypesInId(boolean useParamTypesInId) {
121     this.useParamTypesInId = useParamTypesInId;
122   }
123   
124   
125   // ==========================================================================
126   // Private utils
127   // ==========================================================================
128   
129   /***
130    * Private util method to create a simple String representation of an
131    * intercepted MethodInvocation instance.
132    * @param mi the intercepted MethodInvocation instance.
133    * @return a String representation of the specified MethodInvocation instance.
134    */
135   private String methodSignature(MethodInvocation mi) {
136     StringBuffer methodSignature = new StringBuffer(ClassUtils.getQualifiedMethodName(mi.getMethod()));
137     Class[]      paramTypes      = mi.getMethod().getParameterTypes();
138     
139     methodSignature.append("(");
140     
141     if (useParamTypesInId) {
142       for (int i = 0; i < paramTypes.length; i++) {
143         if (i > 0) {
144           methodSignature.append(",");
145         }
146 
147         methodSignature.append(getShortName(paramTypes[i]));
148       }
149     }
150     
151     methodSignature.append(")");
152     
153     return methodSignature.toString();
154   }
155 
156   /***
157    * Util method to get the short name for the specified class.
158    * 
159    * @param clazz The class instance to use.
160    * @return the class name without its package name.
161    */
162   private String getShortName(Class clazz) {
163     String  name = clazz.getName();
164     Package pack = clazz.getPackage();
165     
166     if (pack != null) {
167       name = StringUtils.delete(name, pack.getName() + ".");
168     }
169     
170     return name;
171   }
172   
173 }