1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.proxy2.stub;
19
20 import java.lang.reflect.Array;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import org.apache.commons.lang3.ArrayUtils;
25 import org.apache.commons.lang3.Validate;
26 import org.apache.commons.lang3.reflect.TypeUtils;
27 import org.apache.commons.proxy2.Interceptor;
28 import org.apache.commons.proxy2.ObjectProvider;
29 import org.apache.commons.proxy2.interceptor.InterceptorUtils;
30 import org.apache.commons.proxy2.interceptor.matcher.ArgumentMatcher;
31 import org.apache.commons.proxy2.interceptor.matcher.argument.ArgumentMatcherUtils;
32
33 public abstract class BaseTrainer<S extends BaseTrainer<S, T>, T>
34 {
35
36
37
38 public final Class<T> traineeType;
39
40
41
42
43
44
45
46
47
48 protected BaseTrainer()
49 {
50 this(null);
51 }
52
53 protected BaseTrainer(Class<T> traineeType)
54 {
55 super();
56 if (traineeType != null)
57 {
58 this.traineeType = traineeType;
59 return;
60 }
61 @SuppressWarnings("unchecked")
62 final Class<T> resolvedVariable = (Class<T>) TypeUtils.getRawType(BaseTrainer.class.getTypeParameters()[1],
63 getClass());
64 Validate.isTrue(resolvedVariable != null, "Trainee type was not specified and could not be calculated for %s",
65 getClass());
66 this.traineeType = resolvedVariable;
67 }
68
69
70
71
72
73 protected abstract void train(T trainee);
74
75
76
77
78
79 protected <R> R any(Class<R> type)
80 {
81 return argThat(ArgumentMatcherUtils.<R> any());
82 }
83
84 protected <R> R eq(R value)
85 {
86 return argThat(ArgumentMatcherUtils.eq(value));
87 }
88
89 protected <R> R isInstance(Class<R> type)
90 {
91 return argThat(ArgumentMatcherUtils.<R> isA(type));
92 }
93
94 protected <R> R argThat(ArgumentMatcher<R> matcher)
95 {
96 trainingContext().record(matcher);
97 return null;
98 }
99
100 protected void thenThrow(Exception e)
101 {
102 trainingContext().then(InterceptorUtils.throwing(e));
103 }
104
105 protected void thenThrow(ObjectProvider<? extends Exception> provider)
106 {
107 trainingContext().then(InterceptorUtils.throwing(provider));
108 }
109
110 protected TrainingContext trainingContext()
111 {
112 return TrainingContext.current();
113 }
114
115 public <R> WhenObject<R> when(R expression)
116 {
117 return new WhenObject<R>();
118 }
119
120 public WhenClass when(Class<?> expression)
121 {
122 return new WhenClass();
123 }
124
125 public WhenByteArray when(byte[] expression)
126 {
127 return new WhenByteArray();
128 }
129
130 public WhenBooleanArray when(boolean[] expression)
131 {
132 return new WhenBooleanArray();
133 }
134
135 public WhenIntArray when(int[] expression)
136 {
137 return new WhenIntArray();
138 }
139
140 public WhenShortArray when(short[] expresssion)
141 {
142 return new WhenShortArray();
143 }
144
145 public WhenLongArray when(long[] expression)
146 {
147 return new WhenLongArray();
148 }
149
150 public WhenFloatArray when(float[] expression)
151 {
152 return new WhenFloatArray();
153 }
154
155 public WhenDoubleArray when(double[] expression)
156 {
157 return new WhenDoubleArray();
158 }
159
160 public <R> WhenObjectArray<R> when(R[] expression)
161 {
162 @SuppressWarnings("unchecked")
163 final Class<? extends R> componentType = (Class<? extends R>) expression.getClass().getComponentType();
164 return new WhenObjectArray<R>(componentType);
165 }
166
167 public WhenCharArray when(char[] expression)
168 {
169 return new WhenCharArray();
170 }
171
172 protected S self()
173 {
174 @SuppressWarnings("unchecked")
175 final S self = (S) this;
176 return self;
177 }
178
179
180
181
182
183 protected abstract class BaseWhen<R>
184 {
185 public S thenThrow(Exception e)
186 {
187 return then(InterceptorUtils.throwing(e));
188 }
189
190 public S thenThrow(ObjectProvider<? extends Exception> provider)
191 {
192 return then(InterceptorUtils.throwing(provider));
193 }
194
195 public S thenAnswer(ObjectProvider<? extends R> provider)
196 {
197 return then(InterceptorUtils.provider(provider));
198 }
199
200 public S then(Interceptor interceptor)
201 {
202 trainingContext().then(interceptor);
203 return self();
204 }
205 }
206
207 protected class WhenBooleanArray extends BaseWhen<boolean[]>
208 {
209 public S thenReturn(boolean... values)
210 {
211 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
212 return self();
213 }
214 }
215
216 protected class WhenByteArray extends BaseWhen<byte[]>
217 {
218 public S thenReturn(byte... values)
219 {
220 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
221 return self();
222 }
223 }
224
225 protected class WhenCharArray extends BaseWhen<char[]>
226 {
227 public S thenReturn(char... values)
228 {
229 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
230 return self();
231 }
232 }
233
234 protected class WhenDoubleArray extends BaseWhen<double[]>
235 {
236 public S thenReturn(double... values)
237 {
238 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
239 return self();
240 }
241 }
242
243 protected class WhenFloatArray extends BaseWhen<float[]>
244 {
245 public S thenReturn(float... values)
246 {
247 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
248 return self();
249 }
250 }
251
252 protected class WhenIntArray extends BaseWhen<int[]>
253 {
254 public S thenReturn(int... values)
255 {
256 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
257 return self();
258 }
259 }
260
261 protected class WhenLongArray extends BaseWhen<long[]>
262 {
263 public S thenReturn(long... values)
264 {
265 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
266 return self();
267 }
268 }
269
270 protected class WhenObject<R> extends BaseWhen<R>
271 {
272 public S thenReturn(R value)
273 {
274 trainingContext().then(InterceptorUtils.constant(value));
275 return self();
276 }
277
278 public S thenStub(BaseTrainer<?, R> trainer)
279 {
280 final R trainee = trainingContext().push(trainer.traineeType);
281 trainer.train(trainee);
282 trainingContext().then(InterceptorUtils.constant(trainingContext().pop()));
283 return self();
284 }
285 }
286
287
288
289
290
291 protected class WhenClass extends BaseWhen<Class<?>>
292 {
293 public S thenReturn(Class<?> value)
294 {
295 trainingContext().then(InterceptorUtils.constant(value));
296 return self();
297 }
298 }
299
300 protected class WhenObjectArray<R> extends BaseWhen<R[]>
301 {
302 protected final Class<? extends R> componentType;
303
304 protected WhenObjectArray(Class<? extends R> componentType)
305 {
306 this.componentType = componentType;
307 }
308
309 public S thenReturn(R... values)
310 {
311 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
312 return self();
313 }
314
315 public StubArrayBuilder<R> thenBuildArray()
316 {
317 return new StubArrayBuilder<R>(componentType);
318 }
319 }
320
321 protected class StubArrayBuilder<R>
322 {
323 protected final List<R> elements = new ArrayList<R>();
324 protected final Class<? extends R> componentType;
325
326 protected StubArrayBuilder(Class<? extends R> componentType)
327 {
328 this.componentType = componentType;
329 }
330
331 public StubArrayBuilder<R> addElement(BaseTrainer<?, R> trainer)
332 {
333 final R trainee = trainingContext().push(trainer.traineeType);
334 trainer.train(trainee);
335 elements.add(trainingContext().<R> pop());
336 return this;
337 }
338
339 public S build()
340 {
341 @SuppressWarnings("unchecked")
342 final R[] array = elements.toArray((R[]) Array.newInstance(componentType, elements.size()));
343 trainingContext().then(InterceptorUtils.constant(array));
344 return self();
345 }
346 }
347
348 protected class WhenShortArray extends BaseWhen<short[]>
349 {
350 public S thenReturn(short... values)
351 {
352 trainingContext().then(InterceptorUtils.constant(ArrayUtils.clone(values)));
353 return self();
354 }
355 }
356 }