1 package com.atlassian.util.profiling.object;
2
3 import com.atlassian.util.profiling.UtilTimerStack;
4
5 import java.lang.reflect.InvocationHandler;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.Proxy;
8 import java.lang.reflect.InvocationTargetException;
9
10 /***
11 * @author <a href="mailto:scott@atlassian.com">Scott Farquhar</a>
12 */
13 public class ObjectProfiler
14 {
15
16 /***
17 * Given a class, and an interface that it implements, return a proxied version of the class that implements
18 * the interface.
19 * <p>
20 * The usual use of this is to profile methods from Factory objects:
21 * <pre>
22 * public PersistenceManager getPersistenceManager()
23 * {
24 * return new DefaultPersistenceManager();
25 * }
26 *
27 * instead write:
28 * public PersistenceManager getPersistenceManager()
29 * {
30 * return ObjectProfiler.getProfiledObject(PersistenceManager.class, new DefaultPersistenceManager());
31 * }
32 * </pre>
33 * <p>
34 * A side effect of this is that you will no longer be able to downcast to DefaultPersistenceManager. This is probably a *good* thing.
35 *
36 * @param interfaceClazz The interface to implement.
37 * @param o The object to proxy
38 * @return A proxied object, or the input object if the interfaceClazz wasn't an interface.
39 */
40 public static Object getProfiledObject(Class interfaceClazz, Object o)
41 {
42 //if we are not active - then do nothing
43 if (!UtilTimerStack.isActive())
44 return o;
45
46 //this should always be true - you shouldn't be passing something that isn't an interface
47 if (interfaceClazz.isInterface())
48 {
49 InvocationHandler timerHandler = new TimerInvocationHandler(o);
50 Object proxy = Proxy.newProxyInstance(interfaceClazz.getClassLoader(),
51 new Class[]{interfaceClazz}, timerHandler);
52 return proxy;
53 }
54 else
55 {
56 return o;
57 }
58 }
59
60 /***
61 * A profiled call {@link Method#invoke(java.lang.Object, java.lang.Object[]). If {@link UtilTimerStack#isActive() }
62 * returns false, then no profiling is performed.
63 */
64 public static Object profiledInvoke(Method target, Object value, Object[] args) throws IllegalAccessException, InvocationTargetException
65 {
66 //if we are not active - then do nothing
67 if (!UtilTimerStack.isActive())
68 return target.invoke(value, args);
69
70 String logLine = new String(getTrimmedClassName(target) + "." + target.getName() + "()");
71
72 UtilTimerStack.push(logLine);
73 try
74 {
75 Object returnValue = target.invoke(value, args);
76
77 //if the return value is an interface then we should also proxy it!
78 if (returnValue != null && target.getReturnType().isInterface())
79 {
80 // System.out.println("Return type " + returnValue.getClass().getName() + " is being proxied " + target.getReturnType().getName() + " " + logLine);
81 InvocationHandler timerHandler = new TimerInvocationHandler(returnValue);
82 Object objectProxy = Proxy.newProxyInstance(returnValue.getClass().getClassLoader(),
83 new Class[]{target.getReturnType()}, timerHandler);
84 return objectProxy;
85 }
86 else
87 {
88 return returnValue;
89 }
90 }
91 finally
92 {
93 UtilTimerStack.pop(logLine);
94 }
95 }
96
97 /***
98 * Given a method, get the Method name, with no package information.
99 */
100 public static String getTrimmedClassName(Method method)
101 {
102 String classname = method.getDeclaringClass().getName();
103 return classname.substring(classname.lastIndexOf('.') + 1);
104 }
105
106 }
107
108 class TimerInvocationHandler implements InvocationHandler
109 {
110 protected Object target;
111
112 public TimerInvocationHandler(Object target)
113 {
114 if (target == null)
115 throw new IllegalArgumentException("Target Object passed to timer cannot be null");
116 this.target = target;
117 }
118
119 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
120 {
121 return ObjectProfiler.profiledInvoke(method, target, args);
122 }
123
124 }
This page was automatically generated by Maven