EMMA Coverage Report (generated Thu Jan 20 11:39:44 EST 2011)
[all classes][com.hammurapi.common]

COVERAGE SUMMARY FOR SOURCE FILE [InvocationRecordingProxyFactory.java]

nameclass, %method, %block, %line, %
InvocationRecordingProxyFactory.java100% (3/3)43%  (6/14)62%  (122/196)64%  (24.9/39)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class InvocationRecordingProxyFactory$InvocationRecord100% (1/1)12%  (1/8)32%  (26/82)50%  (9/18)
getArguments (): Object [] 0%   (0/1)0%   (0/3)0%   (0/1)
getMethod (): Method 0%   (0/1)0%   (0/3)0%   (0/1)
getStackTrace (): StackTraceElement [] 0%   (0/1)0%   (0/3)0%   (0/1)
getTarget (): Object 0%   (0/1)0%   (0/3)0%   (0/1)
getThread (): Thread 0%   (0/1)0%   (0/3)0%   (0/1)
getTimestamp (): long 0%   (0/1)0%   (0/3)0%   (0/1)
toString (): String 0%   (0/1)0%   (0/38)0%   (0/3)
InvocationRecordingProxyFactory$InvocationRecord (Thread, StackTraceElement [... 100% (1/1)100% (26/26)100% (9/9)
     
class InvocationRecordingProxyFactory$RecordingInvocationHandler100% (1/1)100% (3/3)83%  (72/87)77%  (13.9/18)
invoke (Object, Method, Object []): Object 100% (1/1)79%  (57/72)66%  (7.9/12)
InvocationRecordingProxyFactory$RecordingInvocationHandler (Object, Invocatio... 100% (1/1)100% (12/12)100% (5/5)
getRecords (): List 100% (1/1)100% (3/3)100% (1/1)
     
class InvocationRecordingProxyFactory100% (1/1)67%  (2/3)89%  (24/27)67%  (2/3)
InvocationRecordingProxyFactory (): void 0%   (0/1)0%   (0/3)0%   (0/1)
getInvocationRecords (Object): List 100% (1/1)100% (5/5)100% (1/1)
wrap (Class, Object, InvocationRecordingProxyFactory$ProblemListener): Object 100% (1/1)100% (19/19)100% (1/1)

1package com.hammurapi.common;
2 
3import java.lang.reflect.InvocationHandler;
4import java.lang.reflect.Method;
5import java.lang.reflect.Proxy;
6import java.util.Arrays;
7import java.util.LinkedList;
8import java.util.List;
9 
10/**
11 * This class creates a proxy which record all invocations of 
12 * the methods of the target object with stack traces, calling threads, timestamps, and arguments.
13 * These records can be used for troubleshooing of concurrency problems.
14 * @author Pavel Vlasov
15 *
16 */
17public class InvocationRecordingProxyFactory {
18        
19        /**
20         * Callback interface to receive problem notifications.
21         * @author Pavel Vlasov
22         *
23         */
24        public interface ProblemListener {
25                
26                void onProblem(Throwable th, List<InvocationRecord> records);
27        }
28        
29        public static class InvocationRecord {
30                
31                @Override
32                public String toString() {
33                        return "InvocationRecord("+method.getName()+") [thread=" + thread + ", method=" + method
34                                        + ", timestamp=" + timestamp + ", arguments="
35                                        + Arrays.toString(arguments) + ", target=" + target + "]";
36                }
37 
38                private Thread thread;
39                private StackTraceElement[] stackTrace;
40                private Method method;
41                private long timestamp;
42                private Object[] arguments;
43                private Object target;
44                                
45                InvocationRecord(Thread thread, StackTraceElement[] stackTrace, Method method, long timestamp, Object[] arguments, Object target) {
46                        super();
47                        this.thread = thread;
48                        this.stackTrace = stackTrace;
49                        this.method = method;
50                        this.timestamp = timestamp;
51                        if (arguments != null) {
52                                this.arguments = Arrays.copyOf(arguments, arguments.length);
53                        }
54                        this.target = target;
55                }
56 
57                public Thread getThread() {
58                        return thread;
59                }
60                
61                public StackTraceElement[] getStackTrace() {
62                        return stackTrace;
63                }
64                
65                public Method getMethod() {
66                        return method;
67                }
68                
69                public long getTimestamp() {
70                        return timestamp;
71                }
72                
73                Object[] getArguments() {
74                        return arguments;
75                }
76                
77                Object getTarget() {
78                        return target;
79                }
80                
81        }
82        
83        private static class RecordingInvocationHandler implements InvocationHandler {
84                
85                private ProblemListener problemListener;
86 
87                RecordingInvocationHandler(Object target, ProblemListener problemListener, LinkedList<InvocationRecord> records) {
88                        this.target = target;
89                        this.problemListener = problemListener;
90                        this.records = records;
91                }
92                
93                private Object target;
94                
95                private LinkedList<InvocationRecord> records;
96 
97                @Override
98                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
99                        
100                        try {
101                                synchronized (records) {
102                                        Thread currentThread = Thread.currentThread();
103                                        records.addFirst(new InvocationRecord(currentThread, currentThread.getStackTrace(), method, System.currentTimeMillis(), args, target));
104                                }
105                                Object ret = method.invoke(target, args);
106                                Class<?> returnType = method.getReturnType();
107                                if (returnType.isInterface()) {
108                                        return Proxy.newProxyInstance(returnType.getClass().getClassLoader(), new Class[] {returnType}, new RecordingInvocationHandler(ret, problemListener, records));
109                                } 
110                                return ret;
111                        } catch (Throwable th) {
112                                if (problemListener!=null) {
113                                        problemListener.onProblem(th, records);
114                                }
115                                throw th;
116                        }
117                }
118                
119                List<InvocationRecord> getRecords() {
120                        return records;
121                }
122                
123        }
124 
125        /**
126         * Wraps target into a proxy for method call recording.
127         * @param <I>
128         * @param <T>
129         * @param target
130         * @param problemListener 
131         * @return
132         */
133        @SuppressWarnings("unchecked")
134        public static <I, T extends I> I wrap(Class<I> proxyType, T target, ProblemListener problemListener) {
135                return (I) Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[] {proxyType}, new RecordingInvocationHandler(target, problemListener, new LinkedList<InvocationRecord>()));
136        }
137        
138        public static List<InvocationRecord> getInvocationRecords(Object proxy) {
139                return ((RecordingInvocationHandler) Proxy.getInvocationHandler(proxy)).getRecords();                
140        }
141        
142}

[all classes][com.hammurapi.common]
EMMA 2.0.5312 EclEmma Fix 2 (C) Vladimir Roubtsov