1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.callbackparams.internal.template;
18
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Proxy;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.IdentityHashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.ListIterator;
31 import java.util.Map;
32 import org.callbackparams.ext.CallbackControlPanel;
33 import org.callbackparams.combine.reflect.Combined;
34
35
36
37
38 public class TestrunCallbacks {
39
40 private static final List
41 new ArrayList();
42 private static final Map
43 new IdentityHashMap();
44 private static final Map
45 new IdentityHashMap();
46
47
48
49
50
51
52 private static final List
53 private static Collection
54
55
56
57
58
59
60 boolean currentlyWrappedWithinAdaptiveRules = false;
61
62 private Collection
63 private CallbackRecord callbackRecord;
64 protected Object[] callbackMethodArguments;
65
66 public static int addMethodParams(Method m) {
67 callbackMethods.add(m);
68 int startIndex = callbackMethodParams.size();
69 for (int i = 0, size = m.getParameterTypes().length ; i < size ; ++i) {
70 callbackMethodParams.add(CallbackRef.newInstance(m, i));
71 }
72 return startIndex;
73 }
74
75 public static void addFieldToInject(Field f) {
76 try {
77 f.setAccessible(true);
78 } catch (SecurityException ignore) {
79
80 }
81 callbackInjectionFields.put(f, CallbackRef.newInstance(f));
82 }
83
84 public static void setCallbackRecord(Collection testRunCombinedRecord) {
85 currentCombinedRecord = testRunCombinedRecord;
86 }
87
88 public static Iterator iterateFields() {
89 return callbackInjectionFields.keySet().iterator();
90 }
91
92 public static Iterator iterateMethods() {
93 return callbackMethods.iterator();
94 }
95
96 public static Collection getCurrentCallbackRecord() {
97 return currentCombinedRecord;
98 }
99
100 private void parseCurrentCombinedRecord() {
101 this.refBackupOfCurrentCombinedRecord = currentCombinedRecord;
102 List callbacks = new ArrayList(currentCombinedRecord.size());
103 for (Iterator i = currentCombinedRecord.iterator(); i.hasNext();) {
104 final Combined combined = Combined
105 .resurrectFromOtherClassLoader(i.next());
106 Object callback = combined.retrieve(this, valuesCache);
107 if (null != callback) {
108 callbacks.add(callback);
109 }
110 }
111 this.callbackRecord = new CallbackRecord(callbacks);
112 }
113
114 private CallbackRecord getCallbackRecord() {
115 if (this.refBackupOfCurrentCombinedRecord != currentCombinedRecord) {
116 parseCurrentCombinedRecord();
117 }
118 return this.callbackRecord;
119 }
120
121 private void setupCallbackMethodArguments() {
122 callbackMethodArguments = callbackMethodParams.toArray(
123 new Object[callbackMethodParams.size()]);
124
125 ListIterator li = Arrays.asList(callbackMethodArguments).listIterator();
126 while (li.hasNext()) {
127 final CallbackRef methodParam = (CallbackRef) li.next();
128 li.set(createCallbackProxy(methodParam));
129 }
130 }
131
132 private void injectCallbackFields() {
133 for (Iterator i = callbackInjectionFields.entrySet().iterator()
134 ; i.hasNext() ;) {
135 Map.Entry
136 Field f = (Field) fieldEntr.getKey();
137 if (f.getDeclaringClass().isInstance(this)) {
138 try {
139 f.set(this, createCallbackProxy(
140 (CallbackRef) fieldEntr.getValue()));
141 } catch (Exception ex) {
142 throw new Error("Callback injection failed for the field "
143 + f.getName() + ": " + ex.getClass().getName()
144 + " - " + ex.getMessage(), ex);
145 }
146 }
147 }
148 }
149
150 private Object createCallbackProxy(final CallbackRef ref) {
151 final Class paramClass = ref.getParamClass();
152 final Class[] interfaces = new Class[] {paramClass};
153
154 if (CallbackControlPanel.class == paramClass
155 || org.callbackparams.CallbackControlPanel.class == paramClass) {
156 return Proxy.newProxyInstance(
157 getClass().getClassLoader(), interfaces,
158 new InvocationHandler() {
159 public Object invoke(Object proxy, Method method, Object[] args)
160 throws Throwable {
161 try {
162 return method.invoke(
163 getCallbackRecord().getCallbackControlPanel(),
164 args);
165 } catch (InvocationTargetException x) {
166 throw x.getTargetException();
167 }
168 }
169 });
170
171
172 } else {
173 return Proxy.newProxyInstance(
174 paramClass.getClassLoader(), interfaces,
175 new InvocationHandler() {
176 CallbackRecord record;
177 InvocationHandler wrappedInvokeHandler;
178 public Object invoke(Object proxy, Method method, Object[] args)
179 throws Throwable {
180 if (getCallbackRecord() != record) {
181 record = getCallbackRecord();
182 wrappedInvokeHandler = record.newCallbackInvoker(ref);
183 }
184 return wrappedInvokeHandler.invoke(proxy, method, args);
185 }
186 });
187 }
188 }
189
190 private void init() throws Exception {
191 if (null == currentCombinedRecord) {
192 ThirdPartyReloadingWorkaround.getInstance()
193 .resurrectSetup(getClass());
194 }
195
196 parseCurrentCombinedRecord();
197 setupCallbackMethodArguments();
198 injectCallbackFields();
199 }
200
201 public TestrunCallbacks() throws Exception {
202 init();
203 }
204 }