1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.statemachine.transition;
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.Arrays;
25
26 import org.apache.mina.statemachine.State;
27 import org.apache.mina.statemachine.StateMachine;
28 import org.apache.mina.statemachine.StateMachineFactory;
29 import org.apache.mina.statemachine.context.StateContext;
30 import org.apache.mina.statemachine.event.Event;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class MethodTransition extends AbstractTransition {
57 private static final Logger LOGGER = LoggerFactory.getLogger(MethodTransition.class);
58
59 private static final Object[] EMPTY_ARGUMENTS = new Object[0];
60
61 private final Method method;
62
63 private final Object target;
64
65
66
67
68
69
70
71
72
73
74 public MethodTransition(Object eventId, State nextState, Method method, Object target) {
75 super(eventId, nextState);
76 this.method = method;
77 this.target = target;
78 }
79
80
81
82
83
84
85
86
87
88 public MethodTransition(Object eventId, Method method, Object target) {
89 this(eventId, null, method, target);
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public MethodTransition(Object eventId, State nextState, Object target) {
107 this(eventId, nextState, eventId.toString(), target);
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 public MethodTransition(Object eventId, Object target) {
124 this(eventId, eventId.toString(), target);
125 }
126
127
128
129
130
131
132
133
134
135
136
137
138 public MethodTransition(Object eventId, String methodName, Object target) {
139 this(eventId, null, methodName, target);
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public MethodTransition(Object eventId, State nextState, String methodName, Object target) {
155 super(eventId, nextState);
156
157 this.target = target;
158
159 Method[] candidates = target.getClass().getMethods();
160 Method result = null;
161 for (int i = 0; i < candidates.length; i++) {
162 if (candidates[i].getName().equals(methodName)) {
163 if (result != null) {
164 throw new AmbiguousMethodException(methodName);
165 }
166 result = candidates[i];
167 }
168 }
169
170 if (result == null) {
171 throw new NoSuchMethodException(methodName);
172 }
173
174 this.method = result;
175 }
176
177
178
179
180 public Method getMethod() {
181 return method;
182 }
183
184
185
186
187 public Object getTarget() {
188 return target;
189 }
190
191
192
193
194 @Override
195 public boolean doExecute(Event event) {
196 Class<?>[] types = method.getParameterTypes();
197
198 if (types.length == 0) {
199 invokeMethod(EMPTY_ARGUMENTS);
200
201 return true;
202 }
203
204 if (types.length > 2 + event.getArguments().length) {
205 return false;
206 }
207
208 Object[] args = new Object[types.length];
209
210 int i = 0;
211
212 if (match(types[i], event, Event.class)) {
213 args[i++] = event;
214 }
215
216 if (i < args.length && match(types[i], event.getContext(), StateContext.class)) {
217 args[i++] = event.getContext();
218 }
219
220 Object[] eventArgs = event.getArguments();
221
222 for (int j = 0; i < args.length && j < eventArgs.length; j++) {
223 if (match(types[i], eventArgs[j], Object.class)) {
224 args[i++] = eventArgs[j];
225 }
226 }
227
228 if (args.length > i) {
229 return false;
230 }
231
232 invokeMethod(args);
233
234 return true;
235 }
236
237 private boolean match(Class<?> paramType, Object arg, Class<?> argType) {
238 if (paramType.isPrimitive()) {
239 if (paramType.equals(Boolean.TYPE)) {
240 return arg instanceof Boolean;
241 }
242
243 if (paramType.equals(Integer.TYPE)) {
244 return arg instanceof Integer;
245 }
246
247 if (paramType.equals(Long.TYPE)) {
248 return arg instanceof Long;
249 }
250
251 if (paramType.equals(Short.TYPE)) {
252 return arg instanceof Short;
253 }
254
255 if (paramType.equals(Byte.TYPE)) {
256 return arg instanceof Byte;
257 }
258
259 if (paramType.equals(Double.TYPE)) {
260 return arg instanceof Double;
261 }
262
263 if (paramType.equals(Float.TYPE)) {
264 return arg instanceof Float;
265 }
266
267 if (paramType.equals(Character.TYPE)) {
268 return arg instanceof Character;
269 }
270 }
271
272 return argType.isAssignableFrom(paramType) && paramType.isAssignableFrom(arg.getClass());
273 }
274
275 private void invokeMethod(Object[] arguments) {
276 try {
277 if (LOGGER.isDebugEnabled()) {
278 LOGGER.debug("Executing method " + method + " with arguments " + Arrays.asList(arguments));
279 }
280
281 method.invoke(target, arguments);
282 } catch (InvocationTargetException ite) {
283 if (ite.getCause() instanceof RuntimeException) {
284 throw (RuntimeException) ite.getCause();
285 }
286
287 throw new MethodInvocationException(method, ite);
288 } catch (IllegalAccessException iae) {
289 throw new MethodInvocationException(method, iae);
290 }
291 }
292
293 @Override
294 public boolean equals(Object o) {
295 if (o == this) {
296 return true;
297 }
298
299 if (!(o instanceof MethodTransition)) {
300 return false;
301 }
302
303 MethodTransition/../../org/apache/mina/statemachine/transition/MethodTransition.html#MethodTransition">MethodTransition that = (MethodTransition) o;
304
305 return method.equals(that.method) && target.equals(that.target);
306 }
307
308 @Override
309 public int hashCode() {
310 int h = 17;
311 h = h*37 + super.hashCode();
312 h = h*37 + method.hashCode();
313 h = h*37 + target.hashCode();
314
315 return h;
316 }
317
318 @Override
319 public String toString() {
320 StringBuilder sb = new StringBuilder();
321
322 sb.append("MethodTransition[");
323 sb.append(super.toString());
324 sb.append(",method=").append(method);
325 sb.append(']');
326
327 return sb.toString();
328 }
329 }