package org.squirrelframework.foundation.fsm.impl;
import java.lang.reflect.Method;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.squirrelframework.foundation.fsm.Action;
import org.squirrelframework.foundation.fsm.StateMachine;
import com.google.common.base.Preconditions;
public class MethodCallActionProxyImpl<T extends StateMachine<T, S, E, C>, S, E, C> implements Action<T, S, E, C> {
private static final Logger logger = LoggerFactory.getLogger(MethodCallActionProxyImpl.class);
private final String methodName;
private final ExecutionContext executionContext;
private Action<T, S, E, C> delegator;
private final int weight;
MethodCallActionProxyImpl(String methodName, ExecutionContext executionContext) {
String[] arrays = StringUtils.split(methodName, ':');
this.methodName = arrays[0];
if(arrays.length>1 && arrays[1].matches("[\\+-]?\\d+")) {
if(arrays[1].startsWith("+"))
arrays[1] = arrays[1].substring(1);
this.weight = Integer.valueOf(arrays[1]);
} else if(arrays.length>1 && arrays[1].equals("ignore")) {
this.weight = Action.IGNORE_WEIGHT;
} else if(methodName.startsWith("before")) {
this.weight = Action.BEFORE_WEIGHT;
} else if(methodName.startsWith("after")) {
this.weight = Action.AFTER_WEIGHT;
} else {
this.weight = Action.NORMAL_WEIGHT;
}
this.executionContext = executionContext;
}
@Override
public void execute(S from, S to, E event, C context, T stateMachine) {
Preconditions.checkNotNull(stateMachine);
getDelegator().execute(from, to, event, context, stateMachine);
}
@SuppressWarnings("unchecked")
private Action<T, S, E, C> getDelegator() {
if(delegator==null) {
Class<?> stateMachineClazz = executionContext.getExecutionTargetType();
Class<?>[] methodParamTypes = executionContext.getMethodCallParamTypes();
Method method = StateMachineBuilderImpl.findMethodCallActionInternal(
stateMachineClazz, methodName, methodParamTypes);
if(method!=null) {
delegator = FSM.newMethodCallAction(method, weight, executionContext);
} else {
if(logger.isInfoEnabled()) {
logger.warn("Cannot find method '"+methodName+"' with parameters '["+
StringUtils.join(executionContext.getMethodCallParamTypes(), ", ")+
"]' in class "+stateMachineClazz+".");
}
delegator = (Action<T, S, E, C>)Action.DUMMY_ACTION;
}
}
return delegator;
}
@Override
public String name() {
return methodName;
}
@Override
public int weight() {
return weight;
}
@Override
public int hashCode() {
return methodName.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if(obj == null)
return false;
if(obj instanceof MethodCallActionImpl &&
MethodCallActionImpl.class.cast(obj).name().equals(methodName))
return true;
if(getClass() != obj.getClass() ||
!methodName.equals(MethodCallActionProxyImpl.class.cast(obj).methodName))
return false;
return true;
}
@Override
final public String toString() {
return "method#"+methodName+":"+weight;
}
@Override
public boolean isAsync() {
return getDelegator().isAsync();
}
@Override
public long timeout() {
return getDelegator().timeout();
}
}