001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.apache.mina.statemachine;
021:
022: import java.lang.reflect.InvocationHandler;
023: import java.lang.reflect.Method;
024: import java.lang.reflect.Proxy;
025:
026: import org.apache.mina.statemachine.context.SingletonStateContextLookup;
027: import org.apache.mina.statemachine.context.StateContext;
028: import org.apache.mina.statemachine.context.StateContextLookup;
029: import org.apache.mina.statemachine.event.DefaultEventFactory;
030: import org.apache.mina.statemachine.event.Event;
031: import org.apache.mina.statemachine.event.EventArgumentsInterceptor;
032: import org.apache.mina.statemachine.event.EventFactory;
033: import org.slf4j.Logger;
034: import org.slf4j.LoggerFactory;
035:
036: /**
037: * Used to create proxies which will forward all method calls on them to a
038: * {@link StateMachine}.
039: *
040: * @author The Apache MINA Project (dev@mina.apache.org)
041: * @version $Rev: 600096 $, $Date: 2007-12-01 05:00:27 -0700 (Sat, 01 Dec 2007) $
042: */
043: public class StateMachineProxyFactory {
044: private static final Logger log = LoggerFactory
045: .getLogger(StateMachineProxyFactory.class);
046:
047: private static final Object[] EMPTY_ARGUMENTS = new Object[0];
048:
049: private StateMachineProxyFactory() {
050: }
051:
052: @SuppressWarnings("unchecked")
053: public static <T> T create(Class<T> iface, StateMachine sm) {
054: return (T) create(new Class[] { iface }, sm);
055: }
056:
057: @SuppressWarnings("unchecked")
058: public static <T> T create(Class<T> iface, StateMachine sm,
059: StateContextLookup contextLookup) {
060: return (T) create(new Class[] { iface }, sm, contextLookup);
061: }
062:
063: @SuppressWarnings("unchecked")
064: public static <T> T create(Class<T> iface, StateMachine sm,
065: StateContextLookup contextLookup,
066: EventArgumentsInterceptor interceptor) {
067: return (T) create(new Class[] { iface }, sm, contextLookup,
068: interceptor, new DefaultEventFactory());
069: }
070:
071: @SuppressWarnings("unchecked")
072: public static <T> T create(Class<T> iface, StateMachine sm,
073: StateContextLookup contextLookup,
074: EventArgumentsInterceptor interceptor,
075: EventFactory eventFactory) {
076: return (T) create(new Class[] { iface }, sm, contextLookup,
077: interceptor, eventFactory);
078: }
079:
080: public static Object create(Class<?>[] ifaces, StateMachine sm) {
081: return create(ifaces, sm, new SingletonStateContextLookup());
082: }
083:
084: public static Object create(Class<?>[] ifaces, StateMachine sm,
085: StateContextLookup contextLookup) {
086: return create(ifaces, sm, contextLookup, null,
087: new DefaultEventFactory());
088: }
089:
090: public static Object create(Class<?>[] ifaces, StateMachine sm,
091: StateContextLookup contextLookup,
092: EventArgumentsInterceptor interceptor,
093: EventFactory eventFactory) {
094:
095: ClassLoader cl = StateMachineProxyFactory.class
096: .getClassLoader();
097: InvocationHandler handler = new MethodInvocationHandler(sm,
098: contextLookup, interceptor, eventFactory);
099:
100: return Proxy.newProxyInstance(cl, ifaces, handler);
101: }
102:
103: private static class MethodInvocationHandler implements
104: InvocationHandler {
105: private final StateMachine sm;
106: private final StateContextLookup contextLookup;
107: private final EventArgumentsInterceptor interceptor;
108: private final EventFactory eventFactory;
109:
110: public MethodInvocationHandler(StateMachine sm,
111: StateContextLookup contextLookup,
112: EventArgumentsInterceptor interceptor,
113: EventFactory eventFactory) {
114:
115: this .contextLookup = contextLookup;
116: this .sm = sm;
117: this .interceptor = interceptor;
118: this .eventFactory = eventFactory;
119: }
120:
121: public Object invoke(Object proxy, Method method, Object[] args)
122: throws Throwable {
123: if ("hashCode".equals(method.getName()) && args == null) {
124: return new Integer(System.identityHashCode(proxy));
125: }
126: if ("equals".equals(method.getName()) && args.length == 1) {
127: return Boolean.valueOf(proxy == args[0]);
128: }
129: if ("toString".equals(method.getName()) && args == null) {
130: return proxy.getClass().getName()
131: + "@"
132: + Integer.toHexString(System
133: .identityHashCode(proxy));
134: }
135:
136: if (log.isDebugEnabled()) {
137: log.debug("Method invoked: " + method);
138: }
139:
140: args = args == null ? EMPTY_ARGUMENTS : args;
141: if (interceptor != null) {
142: args = interceptor.modify(args);
143: }
144:
145: StateContext context = contextLookup.lookup(args);
146:
147: if (context == null) {
148: throw new IllegalStateException(
149: "Cannot determine state "
150: + "context for method invocation: "
151: + method);
152: }
153:
154: Event event = eventFactory.create(context, method, args);
155:
156: sm.handle(event);
157:
158: return null;
159: }
160: }
161: }
|