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.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36
37
38
39
40
41
42
43 public class StateMachineProxyFactory {
44 private static final Logger log = LoggerFactory.getLogger(StateMachineProxyFactory.class);
45
46 private static final Object[] EMPTY_ARGUMENTS = new Object[0];
47
48 private StateMachineProxyFactory() {
49 }
50
51 @SuppressWarnings("unchecked")
52 public static <T> T create(Class<T> iface, StateMachine sm) {
53 return (T) create(new Class[] { iface }, sm);
54 }
55
56 @SuppressWarnings("unchecked")
57 public static <T> T create(Class<T> iface, StateMachine sm, StateContextLookup contextLookup) {
58 return (T) create(new Class[] { iface }, sm, contextLookup);
59 }
60
61 @SuppressWarnings("unchecked")
62 public static <T> T create(Class<T> iface, StateMachine sm, StateContextLookup contextLookup,
63 EventArgumentsInterceptor interceptor) {
64 return (T) create(new Class[] { iface }, sm, contextLookup, interceptor, new DefaultEventFactory());
65 }
66
67 @SuppressWarnings("unchecked")
68 public static <T> T create(Class<T> iface, StateMachine sm, StateContextLookup contextLookup,
69 EventArgumentsInterceptor interceptor, EventFactory eventFactory) {
70 return (T) create(new Class[] { iface }, sm, contextLookup, interceptor, eventFactory);
71 }
72
73 public static Object create(Class<?>[] ifaces, StateMachine sm) {
74 return create(ifaces, sm, new SingletonStateContextLookup());
75 }
76
77 public static Object create(Class<?>[] ifaces, StateMachine sm, StateContextLookup contextLookup) {
78 return create(ifaces, sm, contextLookup, null, new DefaultEventFactory());
79 }
80
81 public static Object create(Class<?>[] ifaces, StateMachine sm, StateContextLookup contextLookup,
82 EventArgumentsInterceptor interceptor, EventFactory eventFactory) {
83
84 ClassLoader cl = StateMachineProxyFactory.class.getClassLoader();
85 InvocationHandler handler = new MethodInvocationHandler(sm, contextLookup, interceptor, eventFactory);
86
87 return Proxy.newProxyInstance(cl, ifaces, handler);
88 }
89
90 private static class MethodInvocationHandler implements InvocationHandler {
91 private final StateMachine sm;
92 private final StateContextLookup contextLookup;
93 private final EventArgumentsInterceptor interceptor;
94 private final EventFactory eventFactory;
95
96 public MethodInvocationHandler(StateMachine sm, StateContextLookup contextLookup,
97 EventArgumentsInterceptor interceptor, EventFactory eventFactory) {
98
99 this.contextLookup = contextLookup;
100 this.sm = sm;
101 this.interceptor = interceptor;
102 this.eventFactory = eventFactory;
103 }
104
105 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
106 if ("hashCode".equals(method.getName()) && args == null) {
107 return new Integer(System.identityHashCode(proxy));
108 }
109 if ("equals".equals(method.getName()) && args.length == 1) {
110 return Boolean.valueOf(proxy == args[0]);
111 }
112 if ("toString".equals(method.getName()) && args == null) {
113 return proxy.getClass().getName() + "@"
114 + Integer.toHexString(System.identityHashCode(proxy));
115 }
116
117 if (log.isDebugEnabled()) {
118 log.debug("Method invoked: " + method);
119 }
120
121 args = args == null ? EMPTY_ARGUMENTS : args;
122 if (interceptor != null) {
123 args = interceptor.modify(args);
124 }
125
126 StateContext context = contextLookup.lookup(args);
127
128 if (context == null) {
129 throw new IllegalStateException("Cannot determine state "
130 + "context for method invocation: " + method);
131 }
132
133 Event event = eventFactory.create(context, method, args);
134
135 sm.handle(event);
136
137 return null;
138 }
139 }
140 }