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;
21
22 import java.lang.reflect.InvocationHandler;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.Proxy;
25
26 import org.apache.mina.statemachine.context.SingletonStateContextLookup;
27 import org.apache.mina.statemachine.context.StateContext;
28 import org.apache.mina.statemachine.context.StateContextLookup;
29 import org.apache.mina.statemachine.event.DefaultEventFactory;
30 import org.apache.mina.statemachine.event.Event;
31 import org.apache.mina.statemachine.event.EventArgumentsInterceptor;
32 import org.apache.mina.statemachine.event.EventFactory;
33 import org.apache.mina.statemachine.event.UnhandledEventException;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37
38
39
40
41
42
43 public class StateMachineProxyBuilder {
44 private static final Logger log = LoggerFactory.getLogger(StateMachineProxyBuilder.class);
45
46 private static final Object[] EMPTY_ARGUMENTS = new Object[0];
47
48 private StateContextLookup contextLookup = new SingletonStateContextLookup();
49
50 private EventFactory eventFactory = new DefaultEventFactory();
51
52 private EventArgumentsInterceptor interceptor = null;
53
54 private boolean ignoreUnhandledEvents = false;
55
56 private boolean ignoreStateContextLookupFailure = false;
57
58 private String name = null;
59
60
61
62
63
64 private ClassLoader defaultCl = null;
65
66 public StateMachineProxyBuilder() {
67 }
68
69
70
71
72
73
74
75
76
77 public StateMachineProxyBuilder setName(String name) {
78 this.name = name;
79 return this;
80 }
81
82
83
84
85
86
87
88
89 public StateMachineProxyBuilder setStateContextLookup(StateContextLookup contextLookup) {
90 this.contextLookup = contextLookup;
91 return this;
92 }
93
94
95
96
97
98
99
100
101 public StateMachineProxyBuilder setEventFactory(EventFactory eventFactory) {
102 this.eventFactory = eventFactory;
103 return this;
104 }
105
106
107
108
109
110
111
112
113 public StateMachineProxyBuilder setEventArgumentsInterceptor(EventArgumentsInterceptor interceptor) {
114 this.interceptor = interceptor;
115 return this;
116 }
117
118
119
120
121
122
123
124
125
126 public StateMachineProxyBuilder setIgnoreUnhandledEvents(boolean b) {
127 this.ignoreUnhandledEvents = b;
128 return this;
129 }
130
131
132
133
134
135
136
137
138
139 public StateMachineProxyBuilder setIgnoreStateContextLookupFailure(boolean b) {
140 this.ignoreStateContextLookupFailure = b;
141 return this;
142 }
143
144
145
146
147
148
149
150
151
152 public StateMachineProxyBuilder setClassLoader(ClassLoader cl) {
153 this.defaultCl = cl;
154 return this;
155 }
156
157
158
159
160
161
162
163
164
165
166 @SuppressWarnings("unchecked")
167 public <T> T create(Class<T> iface, StateMachine sm) {
168 return (T) create(new Class[] { iface }, sm);
169 }
170
171
172
173
174
175
176
177
178
179
180 public Object create(Class<?>[] ifaces, StateMachine sm) {
181 ClassLoader cl = defaultCl;
182 if (cl == null) {
183 cl = Thread.currentThread().getContextClassLoader();
184 }
185
186 InvocationHandler handler = new MethodInvocationHandler(sm, contextLookup, interceptor, eventFactory,
187 ignoreUnhandledEvents, ignoreStateContextLookupFailure, name);
188
189 return Proxy.newProxyInstance(cl, ifaces, handler);
190 }
191
192 private static class MethodInvocationHandler implements InvocationHandler {
193 private final StateMachine sm;
194
195 private final StateContextLookup contextLookup;
196
197 private final EventArgumentsInterceptor interceptor;
198
199 private final EventFactory eventFactory;
200
201 private final boolean ignoreUnhandledEvents;
202
203 private final boolean ignoreStateContextLookupFailure;
204
205 private final String name;
206
207 public MethodInvocationHandler(StateMachine sm, StateContextLookup contextLookup,
208 EventArgumentsInterceptor interceptor, EventFactory eventFactory, boolean ignoreUnhandledEvents,
209 boolean ignoreStateContextLookupFailure, String name) {
210
211 this.contextLookup = contextLookup;
212 this.sm = sm;
213 this.interceptor = interceptor;
214 this.eventFactory = eventFactory;
215 this.ignoreUnhandledEvents = ignoreUnhandledEvents;
216 this.ignoreStateContextLookupFailure = ignoreStateContextLookupFailure;
217 this.name = name;
218 }
219
220 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
221 if ("hashCode".equals(method.getName()) && args == null) {
222 return new Integer(System.identityHashCode(proxy));
223 }
224 if ("equals".equals(method.getName()) && args.length == 1) {
225 return Boolean.valueOf(proxy == args[0]);
226 }
227 if ("toString".equals(method.getName()) && args == null) {
228 return (name != null ? name : proxy.getClass().getName()) + "@"
229 + Integer.toHexString(System.identityHashCode(proxy));
230 }
231
232 if (log.isDebugEnabled()) {
233 log.debug("Method invoked: " + method);
234 }
235
236 args = args == null ? EMPTY_ARGUMENTS : args;
237 if (interceptor != null) {
238 args = interceptor.modify(args);
239 }
240
241 StateContext context = contextLookup.lookup(args);
242
243 if (context == null) {
244 if (ignoreStateContextLookupFailure) {
245 return null;
246 }
247 throw new IllegalStateException("Cannot determine state " + "context for method invocation: " + method);
248 }
249
250 Event event = eventFactory.create(context, method, args);
251
252 try {
253 sm.handle(event);
254 } catch (UnhandledEventException uee) {
255 if (!ignoreUnhandledEvents) {
256 throw uee;
257 }
258 }
259
260 return null;
261 }
262 }
263 }