/
DefaultInteraction.java
executable file
·159 lines (137 loc) · 5.03 KB
/
DefaultInteraction.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package fitnesse.slim.fixtureInteraction;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import fitnesse.slim.ConverterSupport;
import fitnesse.slim.MethodExecutionResult;
import fitnesse.slim.SlimError;
import fitnesse.slim.SlimServer;
public class DefaultInteraction implements FixtureInteraction {
private static final Method AROUND_METHOD;
static {
try {
AROUND_METHOD = InteractionAwareFixture.class.getMethod("aroundSlimInvoke", FixtureInteraction.class, Method.class, Object[].class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Override
public Object createInstance(List<String> paths, String className, Object[] args)
throws IllegalArgumentException, InstantiationException,
IllegalAccessException, InvocationTargetException {
Class<?> k = searchPathsForClass(paths, className);
Constructor<?> constructor = getConstructor(k, args);
if (constructor == null) {
throw new SlimError(String.format("message:<<%s %s>>",
SlimServer.NO_CONSTRUCTOR, className));
}
return newInstance(args, constructor);
}
private Object newInstance(Object[] args, Constructor<?> constructor)
throws IllegalAccessException, InstantiationException,
InvocationTargetException {
Object[] initargs = ConverterSupport.convertArgs(args,
constructor.getParameterTypes());
return newInstance(constructor, initargs);
}
protected Class<?> searchPathsForClass(List<String> paths, String className) {
Class<?> k = getClass(className);
if (k != null) {
return k;
}
for (String path : paths) {
k = getClass(path + "." + className);
if (k != null) {
return k;
}
}
throw new SlimError(String.format("message:<<%s %s>>", SlimServer.NO_CLASS, className));
}
protected Class<?> getClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}
}
protected Constructor<?> getConstructor(Class<?> clazz,
Object[] args) {
for (Constructor<?> constructor : clazz.getConstructors()) {
Class<?>[] arguments = constructor.getParameterTypes();
if (arguments.length == args.length) {
return constructor;
}
}
return null;
}
protected Object newInstance(Constructor<?> constructor, Object... initargs) throws InvocationTargetException, InstantiationException, IllegalAccessException {
return constructor.newInstance(initargs);
}
@Override
public MethodExecutionResult findAndInvoke(String methodName, Object instance, Object... args) throws Throwable {
Method method = findMatchingMethod(methodName, instance, args);
if (method != null) {
return this.invokeMethod(instance, method, args);
}
return MethodExecutionResult.noMethod(methodName, instance.getClass(), args.length);
}
protected Method findMatchingMethod(String methodName, Object instance, Object... args) {
Class<?> k = instance.getClass();
Method[] methods = k.getMethods();
int nArgs = args.length;
for (Method method : methods) {
boolean hasMatchingName = method.getName().equals(methodName);
boolean hasMatchingArguments = method.getParameterTypes().length == nArgs;
if (hasMatchingName && hasMatchingArguments) {
return method;
}
}
return null;
}
protected MethodExecutionResult invokeMethod(Object instance, Method method, Object[] args) throws Throwable {
Object[] convertedArgs = convertArgs(method, args);
Object retval = callMethod(instance, method, convertedArgs);
Class<?> retType = method.getReturnType();
return new MethodExecutionResult(retval, retType);
}
protected Object[] convertArgs(Method method, Object[] args) {
Type[] argumentParameterTypes = method.getGenericParameterTypes();
return ConverterSupport.convertArgs(args, argumentParameterTypes);
}
protected Object callMethod(Object instance, Method method, Object[] convertedArgs) throws Throwable {
try {
Object result;
if (instance instanceof InteractionAwareFixture) {
// invoke via interaction, so it can also do its thing on the aroundMethod invocation
Object[] args = { this, method, convertedArgs };
result = methodInvoke(AROUND_METHOD, instance, args);
} else {
result = methodInvoke(method, instance, convertedArgs);
}
return result;
} catch (InvocationTargetException e) {
if (e.getCause() != null) {
throw e.getCause();
} else {
throw e.getTargetException();
}
}
}
@Override
public Object methodInvoke(Method method, Object instance, Object... convertedArgs) throws Throwable {
try {
return method.invoke(instance, convertedArgs);
} catch (InvocationTargetException e) {
if (e.getCause() != null) {
throw e.getCause();
} else {
throw e.getTargetException();
}
} catch (IllegalArgumentException e) {
throw new RuntimeException("Bad call of: " + method.getDeclaringClass().getName() + "." + method.getName()
+ ". On instance of: " + instance.getClass().getName(), e);
}
}
}