package org.squirrelframework.foundation.fsm;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.squirrelframework.foundation.component.SquirrelProvider;
import org.squirrelframework.foundation.util.TypeReference;
/**
* State machine builder factory to create the state machine builder. Here we use {@link SquirrelProvider} to create the
* builder, so user can register different implementation class of {@link StateMachineBuilder} to instantiate different
* builder. And also user can register different type of post processor to post process created builder.
*
* @author Henry.He
*
*/
public class StateMachineBuilderFactory {
public static UntypedStateMachineBuilder create(Class<? extends UntypedStateMachine> stateMachineClazz) {
return create(stateMachineClazz, new Class[0]);
}
public static UntypedStateMachineBuilder create(Class<? extends UntypedStateMachine> stateMachineClazz,
Class<?>... extraConstParamTypes) {
final StateMachineBuilder<UntypedStateMachine, Object, Object, Object> builder =
create(stateMachineClazz, Object.class, Object.class, Object.class, extraConstParamTypes);
return create(builder);
}
public static UntypedStateMachineBuilder create(
final StateMachineBuilder<UntypedStateMachine, Object, Object, Object> builder) {
return (UntypedStateMachineBuilder) Proxy.newProxyInstance(
UntypedStateMachineBuilder.class.getClassLoader(),
new Class[]{UntypedStateMachineBuilder.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try {
String methodName = method.getName();
if(methodName.equals("newUntypedStateMachine") || methodName.equals("newAnyStateMachine")) {
Object fsmInstance = null;
if(args.length==3 && StateMachineConfiguration.class.isAssignableFrom(args[1].getClass()) &&
(args[2]==null || args[2].getClass().isArray())) {
fsmInstance = builder.newStateMachine(args[0],
(StateMachineConfiguration)args[1], (Object[])args[2]);
} else if(args.length==2 && (args[1]==null || args[1].getClass().isArray())) {
fsmInstance = builder.newStateMachine(args[0], (Object[])args[1]);
} else if(args.length==1) {
fsmInstance = builder.newStateMachine(args[0]);
} else {
throw new IllegalArgumentException("Illegal argument number.");
}
return fsmInstance;
}
return method.invoke(builder, args);
} catch(InvocationTargetException e) {
throw e.getTargetException();
}
}
});
}
public static <T extends StateMachine<T, S, E, C>, S, E, C> StateMachineBuilder<T, S, E, C> create(
Class<? extends T> stateMachineClazz, Class<S> stateClazz, Class<E> eventClazz, Class<C> contextClazz) {
return create(stateMachineClazz, stateClazz, eventClazz, contextClazz, new Class<?>[0]);
}
public static <T extends StateMachine<T, S, E, C>, S, E, C> StateMachineBuilder<T, S, E, C> create(
Class<? extends T> stateMachineClazz, Class<S> stateClazz, Class<E> eventClazz, Class<C> contextClazz,
Class<?>... extraConstParamTypes) {
return SquirrelProvider.getInstance().newInstance(new TypeReference<StateMachineBuilder<T, S, E, C>>() {},
new Class[] { Class.class, Class.class, Class.class, Class.class, Class[].class },
new Object[] { stateMachineClazz, stateClazz, eventClazz, contextClazz, extraConstParamTypes });
}
}