Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.statemachine;

import org.slf4j.Logger;
Expand All @@ -37,13 +38,13 @@ public class StateMachine {

private static final String HANDLER_METHOD_NAME = "handleEvent";

private static ConcurrentHashMap<Class<?>, ConcurrentHashMap<Class<?>, Method>> stateCaches;
private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<Class<?>, Method>> stateCaches;

static {
stateCaches = new ConcurrentHashMap<>();
}

public static abstract class State {
public abstract static class State {

protected final Fsm fsm;
private final ConcurrentHashMap<Class<?>, Method> handlerCache;
Expand All @@ -62,7 +63,7 @@ public State(Fsm fsm) {
this.handlerCache = handlerCache;
}

private Method findHandlerInternal(Class<?> state, Class<?> e) throws NoSuchMethodException {
private Method findHandlerInternal(Class<?> state, Class<?> exception) throws NoSuchMethodException {
Method[] methods = state.getMethods();
List<Method> candidates = new ArrayList<>();
for (Method m : methods) {
Expand All @@ -75,7 +76,7 @@ private Method findHandlerInternal(Class<?> state, Class<?> e) throws NoSuchMeth

Method best = null;
for (Method m : candidates) {
if (m.getParameterTypes()[0].isAssignableFrom(e)) {
if (m.getParameterTypes()[0].isAssignableFrom(exception)) {
if (best == null) {
best = m;
} else if (best.getParameterTypes()[0]
Expand All @@ -92,19 +93,19 @@ private Method findHandlerInternal(Class<?> state, Class<?> e) throws NoSuchMeth
}

private Method findHandler(Class<?> event) throws NoSuchMethodException {
Method m = handlerCache.get(event);
if (m == null) {
m = findHandlerInternal(getClass(), event);
Method m2 = handlerCache.putIfAbsent(event, m);
Method method = handlerCache.get(event);
if (method == null) {
method = findHandlerInternal(getClass(), event);
Method m2 = handlerCache.putIfAbsent(event, method);
if (m2 != null) {
m = m2;
method = m2;
}
}
return m;
return method;
}

State dispatch(Event e) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return (State) findHandler(e.getClass()).invoke(this, e);
State dispatch(Event event) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return (State) findHandler(event.getClass()).invoke(this, event);
}

}
Expand All @@ -117,11 +118,11 @@ public interface Fsm {

void setInitState(State initState);

void sendEvent(Event e);
void sendEvent(Event event);

Future<?> sendEvent(Event e, long delay, TimeUnit unit);
Future<?> sendEvent(Event event, long delay, TimeUnit unit);

void deferEvent(DeferrableEvent e);
void deferEvent(DeferrableEvent deferrableEvent);
}

public static class FsmImpl implements Fsm {
Expand All @@ -135,12 +136,12 @@ public FsmImpl(ScheduledExecutorService executor) {
deferred = new ArrayDeque<>();
}

private void errorDeferredEvents(Throwable t) {
private void errorDeferredEvents(Throwable exception) {
Queue<DeferrableEvent> oldDeferred = deferred;
deferred = new ArrayDeque<>();

for (DeferrableEvent e : oldDeferred) {
e.error(new IllegalStateException(t));
e.error(new IllegalStateException(exception));
}
}

Expand Down Expand Up @@ -172,16 +173,16 @@ void setState(final State curState, final State newState) {
}
}

boolean processEvent(Event e) {
boolean processEvent(Event event) {
if (LOG.isDebugEnabled()) {
LOG.debug("FSM-{}: Received event {}@{} in state {}@{}",
getFsmId(), e.getClass().getSimpleName(),
System.identityHashCode(e),
getFsmId(), event.getClass().getSimpleName(),
System.identityHashCode(event),
state.getClass().getSimpleName(),
System.identityHashCode(state));
}
try {
State newState = state.dispatch(e);
State newState = state.dispatch(event);

if (newState != state) {
setState(state, newState);
Expand All @@ -195,15 +196,15 @@ boolean processEvent(Event e) {
}

class FSMRunnable implements Runnable {
final Event e;
final Event event;

FSMRunnable(Event e) {
this.e = e;
FSMRunnable(Event event) {
this.event = event;
}

@Override
public void run() {
boolean stateChanged = processEvent(e);
boolean stateChanged = processEvent(event);
while (stateChanged) {
stateChanged = false;
Queue<DeferrableEvent> prevDeferred = deferred;
Expand All @@ -220,33 +221,29 @@ public void run() {
}

@Override
public void sendEvent(final Event e) {
executor.submit(new FSMRunnable(e));
public void sendEvent(final Event event) {
executor.submit(new FSMRunnable(event));
}

@Override
public Future<?> sendEvent(final Event e, final long delay, final TimeUnit unit) {
return executor.schedule(new FSMRunnable(e), delay, unit);
public Future<?> sendEvent(final Event event, final long delay, final TimeUnit unit) {
return executor.schedule(new FSMRunnable(event), delay, unit);
}

@Override
public void deferEvent(DeferrableEvent e) {
public void deferEvent(DeferrableEvent deferrableEvent) {
if (LOG.isDebugEnabled()) {
LOG.debug("FSM-{}: deferred {}@{}",
getFsmId(), e.getClass().getSimpleName(), System.identityHashCode(e));
LOG.debug("FSM-{}: deferred {}@{}", getFsmId(),
deferrableEvent.getClass().getSimpleName(),
System.identityHashCode(deferrableEvent));
}
deferred.add(e);
deferred.add(deferrableEvent);
}

int getFsmId() {
return System.identityHashCode(this);
}

@Override
protected void finalize() throws Throwable {
super.finalize();
LOG.debug("FSM-{}: Finalizing", getFsmId());
}
}

public interface DeferrableEvent extends Event {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.statemachine;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -35,19 +36,19 @@ public class StateMachineLogParser {

static Pattern fsmPattern = Pattern.compile("FSM-(\\d+):");

static Map<String, List<String>> getFsmEventMap(BufferedReader f) throws IOException {
String s = f.readLine();
Map<String, List<String>> map = new HashMap<String, List<String>>();
while (s != null) {
Matcher m = fsmPattern.matcher(s);
if (m.find()) {
String key = m.group(1);
static Map<String, List<String>> getFsmEventMap(BufferedReader reader) throws IOException {
String line = reader.readLine();
Map<String, List<String>> map = new HashMap<>();
while (line != null) {
Matcher matcher = fsmPattern.matcher(line);
if (matcher.find()) {
String key = matcher.group(1);
if (!map.containsKey(key)) {
map.put(key, new ArrayList<String>());
}
map.get(key).add(s);
map.get(key).add(line);
}
s = f.readLine();
line = reader.readLine();
}
return map;
}
Expand All @@ -64,12 +65,12 @@ static class Tuple {
}

@Override
public boolean equals(Object o) {
if (o instanceof Tuple) {
Tuple t = (Tuple) o;
return state1.equals(t.state1)
&& state2.equals(t.state2)
&& event.equals(t.event);
public boolean equals(Object obj) {
if (obj instanceof Tuple) {
Tuple tuple = (Tuple) obj;
return state1.equals(tuple.state1)
&& state2.equals(tuple.state2)
&& event.equals(tuple.event);
}
return false;
}
Expand All @@ -89,13 +90,13 @@ public String toString() {
static Pattern subclassPattern = Pattern.compile("(.+)\\$(.+)");

static String cleanupState(String state) {
Matcher m = hashcodePattern.matcher(state);
if (m.find()) {
state = m.group(1);
Matcher matcher = hashcodePattern.matcher(state);
if (matcher.find()) {
state = matcher.group(1);
}
m = subclassPattern.matcher(state);
if (m.find()) {
state = m.group(2);
matcher = subclassPattern.matcher(state);
if (matcher.find()) {
state = matcher.group(2);
}
return state;
}
Expand All @@ -104,23 +105,23 @@ static String cleanupState(String state) {
static Pattern transitionPattern = Pattern.compile("State transition (.+) -> (.+)");

static Set<Tuple> getStateTuples(Map<String, List<String>> fsms) {
Set<Tuple> tuples = new HashSet<Tuple>();
Set<Tuple> tuples = new HashSet<>();
for (List<String> transitions : fsms.values()) {
String currentEvent = null;
for (String s : transitions) {
//System.err.println(s);
Matcher m = eventPattern.matcher(s);
if (m.find()) {
currentEvent = m.group(1);
Matcher matcher = eventPattern.matcher(s);
if (matcher.find()) {
currentEvent = matcher.group(1);
continue;
}
m = transitionPattern.matcher(s);
if (m.find()) {
matcher = transitionPattern.matcher(s);
if (matcher.find()) {
if (currentEvent == null) {
System.err.println("event is null");
}
String state1 = m.group(1);
String state2 = m.group(2);
String state1 = matcher.group(1);
String state2 = matcher.group(2);
tuples.add(new Tuple(cleanupState(state1),
currentEvent,
cleanupState(state2)));
Expand All @@ -135,7 +136,7 @@ static Set<Tuple> getStateTuples(Map<String, List<String>> fsms) {
}

static void drawDotGraph(Set<Tuple> tuples) {
Set<String> states = new HashSet<String>();
Set<String> states = new HashSet<>();
for (Tuple t : tuples) {
states.add(t.state1);
states.add(t.state2);
Expand All @@ -156,8 +157,9 @@ public static void main(String[] args) throws Exception {
System.out.println("Usage: StateMachineLogParser <logfile> | dot -Tsvg ");
System.exit(-1);
}
BufferedReader f = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]), Charset.forName("UTF-8")));
Map<String, List<String>> fsms = getFsmEventMap(f);
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]),
StandardCharsets.UTF_8));
Map<String, List<String>> fsms = getFsmEventMap(reader);
Set<Tuple> tuples = getStateTuples(fsms);
drawDotGraph(tuples);
}
Expand Down
Loading