com.rabidgremlin.mutters.state.StateMachine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mutters-statemachine-bot Show documentation
Show all versions of mutters-statemachine-bot Show documentation
A framework for building bots.
package com.rabidgremlin.mutters.state;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import com.rabidgremlin.mutters.core.Intent;
import com.rabidgremlin.mutters.core.IntentMatch;
import com.rabidgremlin.mutters.core.session.Session;
public class StateMachine
{
private HashMap states = new HashMap();
private State startState;
private HashMap> transitionMap = new HashMap>();
private HashSet handledIntents = new HashSet();
private HashMap preEventActions = new HashMap();
class Transition
{
private State toState;
private Guard guard;
Transition(State toState, Guard guard)
{
this.toState = toState;
this.guard = guard;
}
public State getToState()
{
return toState;
}
public void setToState(State toState)
{
this.toState = toState;
}
public Guard getGuard()
{
return guard;
}
public void setGuard(Guard guard)
{
this.guard = guard;
}
}
public void setStartState(State state)
{
this.startState = state;
}
private void addState(State state)
{
states.put(state.getName(), state);
if (startState == null)
{
startState = state;
}
}
private String makeTransitionKey(String intentName, State state)
{
return intentName + '-' + state.getName();
}
private String makeGlobalTransitionKey(String intentName)
{
return intentName + "-*";
}
public void addTransition(String intentName, State fromState, State toState)
{
addTransition(intentName, fromState, toState, null);
}
public void addPreEventAction(String intentName, State fromState, PreEventAction preEventAction)
{
preEventActions.put(makeTransitionKey(intentName, fromState), preEventAction);
}
public void addTransition(String intentName, State fromState, State toState, Guard guard)
{
if (!states.containsKey(fromState.getName()))
{
addState(fromState);
}
if (!states.containsKey(toState.getName()))
{
addState(toState);
}
String key = makeTransitionKey(intentName, fromState);
List transitionList = transitionMap.get(key);
if (transitionList == null)
{
transitionList = new ArrayList();
transitionMap.put(key, transitionList);
}
transitionList.add(new Transition(toState, guard));
handledIntents.add(intentName);
}
public void addGlobalTransition(String intentName, State toState)
{
addGlobalTransition(intentName, toState, null);
}
public void addGlobalTransition(String intentName, State toState, Guard guard)
{
if (!states.containsKey(toState.getName()))
{
addState(toState);
}
String key = makeGlobalTransitionKey(intentName);
List transitionList = transitionMap.get(key);
if (transitionList == null)
{
transitionList = new ArrayList();
transitionMap.put(key, transitionList);
}
transitionList.add(new Transition(toState, guard));
handledIntents.add(intentName);
}
public IntentResponse trigger(final IntentMatch match, final Session session)
{
State currentState = startState;
String currentStateName = (String) session
.getAttribute("STATE_MACHINE_JLA1974_currentStateName");
if (currentStateName != null)
{
currentState = states.get(currentStateName);
if (currentState == null)
{
throw new IllegalStateException("Illegal current state in session:" + currentStateName);
}
}
Intent intent = match.getIntent();
String intentName = (intent != null) ? intent.getName() : null;
if (intentName == null)
{
throw new IllegalArgumentException("Request missing intent." + match.toString());
}
String key = makeTransitionKey(intentName, currentState);
// see if we have a pre-evet action and execute it if we have it
PreEventAction preEventAction = preEventActions.get(key);
if (preEventAction != null)
{
preEventAction.execute(match, session);
}
List transitionToStateList = transitionMap.get(key);
if (transitionToStateList == null)
{
key = makeGlobalTransitionKey(intentName);
transitionToStateList = transitionMap.get(key);
if (transitionToStateList == null)
{
throw new IllegalStateException("Could not find state to transition to. Intent: "
+ intentName + " Current State: " + currentState);
}
}
State transitionToState = null;
// find first matching to state, checking guards
for (Transition transition : transitionToStateList)
{
if (transition.guard == null)
{
transitionToState = transition.toState;
break;
}
else
{
if (transition.guard.passes(match, session))
{
transitionToState = transition.toState;
break;
}
}
}
// didn't find any matching states
if (transitionToState == null)
{
throw new IllegalStateException(
"Could not find state to transition to. Failed all guards. Intent: " + intentName
+ " Current State: " + currentState);
}
IntentResponse response = transitionToState.execute(match, session);
session.setAttribute("STATE_MACHINE_JLA1974_currentStateName", transitionToState.name);
return response;
}
public boolean canHandleRequest(final IntentMatch request)
{
return request.getIntent() != null && handledIntents.contains(request.getIntent().getName());
}
public void dump(Writer writer)
throws IOException
{
// dummy state for global transitions
final State anyState = new State("<>")
{
@Override
public IntentResponse execute(IntentMatch intentMatch, Session session)
{
return null;
}
};
PrintWriter out = new PrintWriter(writer);
out.println("digraph g {");
out.println("rankdir=LR;");
out.println("overlap=false;");
out.println("nodesep=0.25;");
for (State state : states.values())
{
out.print(state.getName());
out.println(";");
}
for (String key : transitionMap.keySet())
{
String[] splitKey = key.split("-");
String intent = splitKey[0];
State fromState;
// handle global transitions
if (splitKey[1].equals("*"))
{
fromState = anyState;
}
else
{
fromState = states.get(splitKey[1]);
}
List transitionToStateList = transitionMap.get(key);
for (Transition transition : transitionToStateList)
{
out.print(fromState.getName());
out.print(" -> ");
out.print(transition.toState.getName());
out.print(" [label=\"");
out.print(intent);
if (transition.guard != null)
{
out.print(" [");
out.print(transition.guard.getDescription());
out.print("]");
}
out.println("\"];");
}
}
out.println("}");
out.flush();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy