You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by el...@apache.org on 2012/07/09 14:54:08 UTC
svn commit: r1359127 - in /mina/branches/2.0/mina-statemachine/src:
main/java/org/apache/mina/statemachine/
main/java/org/apache/mina/statemachine/annotation/
main/java/org/apache/mina/statemachine/transition/
test/java/org/apache/mina/statemachine/
Author: elecharny
Date: Mon Jul 9 12:54:07 2012
New Revision: 1359127
URL: http://svn.apache.org/viewvc?rev=1359127&view=rev
Log:
Applied patch for DIRMINA-847
Added:
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnEntry.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnExit.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/AbstractSelfTransition.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/MethodSelfTransition.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/SelfTransition.java
Modified:
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/State.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachine.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachineFactory.java
mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/TransitionAnnotation.java
mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineProxyBuilderTest.java
mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineTest.java
Modified: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/State.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/State.java?rev=1359127&r1=1359126&r2=1359127&view=diff
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/State.java (original)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/State.java Mon Jul 9 12:54:07 2012
@@ -27,6 +27,7 @@ import org.apache.commons.lang.builder.E
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.mina.statemachine.event.Event;
+import org.apache.mina.statemachine.transition.SelfTransition;
import org.apache.mina.statemachine.transition.Transition;
/**
@@ -48,10 +49,17 @@ import org.apache.mina.statemachine.tran
*/
public class State {
private final String id;
+
private final State parent;
+
private List<TransitionHolder> transitionHolders = new ArrayList<TransitionHolder>();
+
private List<Transition> transitions = Collections.emptyList();
-
+
+ private List<SelfTransition> onEntries = new ArrayList<SelfTransition>();
+
+ private List<SelfTransition> onExits = new ArrayList<SelfTransition>();
+
/**
* Creates a new {@link State} with the specified id.
*
@@ -101,13 +109,59 @@ public class State {
return Collections.unmodifiableList(transitions);
}
+ /**
+ * Returns an unmodifiable {@link List} of entry {@link SelfTransition}s
+ *
+ * @return the {@link SelfTransition}s.
+ */
+ public List<SelfTransition> getOnEntrySelfTransitions() {
+ return Collections.unmodifiableList(onEntries);
+ }
+
+ /**
+ * Returns an unmodifiable {@link List} of exit {@link SelfTransition}s
+ *
+ * @return the {@link SelfTransition}s.
+ */
+ public List<SelfTransition> getOnExitSelfTransitions() {
+ return Collections.unmodifiableList(onExits);
+ }
+
+ /**
+ * Adds an entry {@link SelfTransition} to this {@link State}
+ *
+ * @param selfTransition the {@link SelfTransition} to add.
+ * @return this {@link State}.
+ */
+ State addOnEntrySelfTransaction(SelfTransition onEntrySelfTransaction) {
+ if (onEntrySelfTransaction == null) {
+ throw new IllegalArgumentException("transition");
+ }
+ onEntries.add(onEntrySelfTransaction);
+ return this;
+ }
+
+ /**
+ * Adds an exit {@link SelfTransition} to this {@link State}
+ *
+ * @param selfTransition the {@link SelfTransition} to add.
+ * @return this {@link State}.
+ */
+ State addOnExitSelfTransaction(SelfTransition onExitSelfTransaction) {
+ if (onExitSelfTransaction == null) {
+ throw new IllegalArgumentException("transition");
+ }
+ onExits.add(onExitSelfTransaction);
+ return this;
+ }
+
private void updateTransitions() {
transitions = new ArrayList<Transition>(transitionHolders.size());
for (TransitionHolder holder : transitionHolders) {
transitions.add(holder.transition);
}
}
-
+
/**
* Adds an outgoing {@link Transition} to this {@link State} with weight 0.
*
@@ -139,7 +193,7 @@ public class State {
updateTransitions();
return this;
}
-
+
@Override
public boolean equals(Object o) {
if (!(o instanceof State)) {
Modified: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachine.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachine.java?rev=1359127&r1=1359126&r2=1359127&view=diff
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachine.java (original)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachine.java Mon Jul 9 12:54:07 2012
@@ -23,12 +23,14 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.apache.mina.statemachine.context.StateContext;
import org.apache.mina.statemachine.event.Event;
import org.apache.mina.statemachine.event.UnhandledEventException;
+import org.apache.mina.statemachine.transition.SelfTransition;
import org.apache.mina.statemachine.transition.Transition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,7 +62,7 @@ public class StateMachine {
return new LinkedList<Event>();
}
};
-
+
/**
* Creates a new instance using the specified {@link State}s and start
* state.
@@ -86,7 +88,7 @@ public class StateMachine {
public StateMachine(Collection<State> states, String startStateId) {
this(states.toArray(new State[0]), startStateId);
}
-
+
/**
* Returns the {@link State} with the specified id.
*
@@ -111,7 +113,7 @@ public class StateMachine {
public Collection<State> getStates() {
return Collections.unmodifiableCollection(states.values());
}
-
+
/**
* Processes the specified {@link Event} through this {@link StateMachine}.
* Normally you wouldn't call this directly but rather use
@@ -135,8 +137,7 @@ public class StateMachine {
* event.
*/
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("State machine called recursively. Queuing event " + event
- + " for later processing.");
+ LOGGER.debug("State machine called recursively. Queuing event " + event + " for later processing.");
}
} else {
processingThreadLocal.set(true);
@@ -160,7 +161,7 @@ public class StateMachine {
handle(context.getCurrentState(), event);
}
}
-
+
private void handle(State state, Event event) {
StateContext context = event.getContext();
@@ -180,8 +181,7 @@ public class StateMachine {
}
} catch (BreakAndContinueException bace) {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndContinueException thrown in "
- + "transition " + t
+ LOGGER.debug("BreakAndContinueException thrown in " + "transition " + t
+ ". Continuing with next transition.");
}
} catch (BreakAndGotoException bage) {
@@ -189,16 +189,14 @@ public class StateMachine {
if (bage.isNow()) {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndGotoException thrown in "
- + "transition " + t + ". Moving to state "
+ LOGGER.debug("BreakAndGotoException thrown in " + "transition " + t + ". Moving to state "
+ newState.getId() + " now.");
}
setCurrentState(context, newState);
handle(newState, event);
} else {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndGotoException thrown in "
- + "transition " + t + ". Moving to state "
+ LOGGER.debug("BreakAndGotoException thrown in " + "transition " + t + ". Moving to state "
+ newState.getId() + " next.");
}
setCurrentState(context, newState);
@@ -208,23 +206,20 @@ public class StateMachine {
State newState = getState(bace.getStateId());
Stack<State> callStack = getCallStack(context);
- State returnTo = bace.getReturnToStateId() != null
- ? getState(bace.getReturnToStateId())
- : context.getCurrentState();
+ State returnTo = bace.getReturnToStateId() != null ? getState(bace.getReturnToStateId()) : context
+ .getCurrentState();
callStack.push(returnTo);
if (bace.isNow()) {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndCallException thrown in "
- + "transition " + t + ". Moving to state "
+ LOGGER.debug("BreakAndCallException thrown in " + "transition " + t + ". Moving to state "
+ newState.getId() + " now.");
}
setCurrentState(context, newState);
handle(newState, event);
} else {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndCallException thrown in "
- + "transition " + t + ". Moving to state "
+ LOGGER.debug("BreakAndCallException thrown in " + "transition " + t + ". Moving to state "
+ newState.getId() + " next.");
}
setCurrentState(context, newState);
@@ -236,16 +231,14 @@ public class StateMachine {
if (bare.isNow()) {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndReturnException thrown in "
- + "transition " + t + ". Moving to state "
+ LOGGER.debug("BreakAndReturnException thrown in " + "transition " + t + ". Moving to state "
+ newState.getId() + " now.");
}
setCurrentState(context, newState);
handle(newState, event);
} else {
if (LOGGER.isDebugEnabled()) {
- LOGGER.debug("BreakAndReturnException thrown in "
- + "transition " + t + ". Moving to state "
+ LOGGER.debug("BreakAndReturnException thrown in " + "transition " + t + ". Moving to state "
+ newState.getId() + " next.");
}
setCurrentState(context, newState);
@@ -284,8 +277,47 @@ public class StateMachine {
LOGGER.debug("Entering state " + newState.getId());
}
}
+ executeOnExits(context, context.getCurrentState());
+ executeOnEntries(context, newState);
context.setCurrentState(newState);
}
}
-
+
+ void executeOnExits(StateContext context, State state) {
+ List<SelfTransition> onExits = state.getOnExitSelfTransitions();
+ boolean isExecuted = false;
+
+ if (onExits != null)
+ for (SelfTransition selfTransition : onExits) {
+ selfTransition.execute(context, state);
+ if (LOGGER.isDebugEnabled()) {
+ isExecuted = true;
+ LOGGER.debug("Executing onEntry action for " + state.getId());
+ }
+ }
+ if (LOGGER.isDebugEnabled() && !isExecuted) {
+ LOGGER.debug("No onEntry action for " + state.getId());
+
+ }
+ }
+
+ void executeOnEntries(StateContext context, State state) {
+ List<SelfTransition> onEntries = state.getOnEntrySelfTransitions();
+ boolean isExecuted = false;
+
+ if (onEntries != null)
+ for (SelfTransition selfTransition : onEntries) {
+ selfTransition.execute(context, state);
+ if (LOGGER.isDebugEnabled()) {
+ isExecuted = true;
+ LOGGER.debug("Executing onExit action for " + state.getId());
+ }
+ }
+ if (LOGGER.isDebugEnabled() && !isExecuted) {
+ LOGGER.debug("No onEntry action for " + state.getId());
+
+ }
+
+ }
+
}
Modified: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachineFactory.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachineFactory.java?rev=1359127&r1=1359126&r2=1359127&view=diff
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachineFactory.java (original)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/StateMachineFactory.java Mon Jul 9 12:54:07 2012
@@ -32,16 +32,19 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import org.apache.mina.statemachine.annotation.OnEntry;
+import org.apache.mina.statemachine.annotation.OnExit;
import org.apache.mina.statemachine.annotation.Transition;
import org.apache.mina.statemachine.annotation.TransitionAnnotation;
import org.apache.mina.statemachine.annotation.Transitions;
import org.apache.mina.statemachine.event.Event;
+import org.apache.mina.statemachine.transition.MethodSelfTransition;
import org.apache.mina.statemachine.transition.MethodTransition;
-
+import org.apache.mina.statemachine.transition.SelfTransition;
/**
* Creates {@link StateMachine}s by reading {@link org.apache.mina.statemachine.annotation.State},
- * {@link Transition} and {@link Transitions} (or equivalent) annotations from one or more arbitrary
+ * {@link Transition} and {@link Transitions} (or equivalent) and {@link SelfTransition} annotations from one or more arbitrary
* objects.
*
*
@@ -49,16 +52,25 @@ import org.apache.mina.statemachine.tran
*/
public class StateMachineFactory {
private final Class<? extends Annotation> transitionAnnotation;
+
private final Class<? extends Annotation> transitionsAnnotation;
- protected StateMachineFactory(Class<? extends Annotation> transitionAnnotation,
- Class<? extends Annotation> transitionsAnnotation) {
+ private final Class<? extends Annotation> entrySelfTransitionsAnnotation;
+
+ private final Class<? extends Annotation> exitSelfTransitionsAnnotation;
+
+ protected StateMachineFactory(Class<? extends Annotation> transitionAnnotation,
+ Class<? extends Annotation> transitionsAnnotation,
+ Class<? extends Annotation> entrySelfTransitionsAnnotation,
+ Class<? extends Annotation> exitSelfTransitionsAnnotation) {
this.transitionAnnotation = transitionAnnotation;
this.transitionsAnnotation = transitionsAnnotation;
+ this.entrySelfTransitionsAnnotation = entrySelfTransitionsAnnotation;
+ this.exitSelfTransitionsAnnotation = exitSelfTransitionsAnnotation;
}
-
+
/**
- * Returns a new {@link StateMachineFactory} instance which creates
+ * Returns a new {@link StateMachineFactory} instance which creates
* {@link StateMachine}s by reading the specified {@link Transition}
* equivalent annotation.
*
@@ -68,18 +80,18 @@ public class StateMachineFactory {
public static StateMachineFactory getInstance(Class<? extends Annotation> transitionAnnotation) {
TransitionAnnotation a = transitionAnnotation.getAnnotation(TransitionAnnotation.class);
if (a == null) {
- throw new IllegalArgumentException("The annotation class "
- + transitionAnnotation + " has not been annotated with the "
- + TransitionAnnotation.class.getName() + " annotation");
+ throw new IllegalArgumentException("The annotation class " + transitionAnnotation
+ + " has not been annotated with the " + TransitionAnnotation.class.getName() + " annotation");
}
- return new StateMachineFactory(transitionAnnotation, a.value());
+ return new StateMachineFactory(transitionAnnotation, a.value(), OnEntry.class, OnExit.class);
+
}
-
+
/**
* Creates a new {@link StateMachine} from the specified handler object and
* using a start state with id <code>start</code>.
*
- * @param handler the object containing the annotations describing the
+ * @param handler the object containing the annotations describing the
* state machine.
* @return the {@link StateMachine} object.
*/
@@ -92,7 +104,7 @@ public class StateMachineFactory {
* using the {@link State} with the specified id as start state.
*
* @param start the id of the start {@link State} to use.
- * @param handler the object containing the annotations describing the
+ * @param handler the object containing the annotations describing the
* state machine.
* @return the {@link StateMachine} object.
*/
@@ -104,34 +116,34 @@ public class StateMachineFactory {
* Creates a new {@link StateMachine} from the specified handler objects and
* using a start state with id <code>start</code>.
*
- * @param handler the first object containing the annotations describing the
+ * @param handler the first object containing the annotations describing the
* state machine.
- * @param handlers zero or more additional objects containing the
+ * @param handlers zero or more additional objects containing the
* annotations describing the state machine.
* @return the {@link StateMachine} object.
*/
public StateMachine create(Object handler, Object... handlers) {
return create("start", handler, handlers);
}
-
+
/**
* Creates a new {@link StateMachine} from the specified handler objects and
* using the {@link State} with the specified id as start state.
*
* @param start the id of the start {@link State} to use.
- * @param handler the first object containing the annotations describing the
+ * @param handler the first object containing the annotations describing the
* state machine.
- * @param handlers zero or more additional objects containing the
+ * @param handlers zero or more additional objects containing the
* annotations describing the state machine.
* @return the {@link StateMachine} object.
*/
public StateMachine create(String start, Object handler, Object... handlers) {
-
+
Map<String, State> states = new HashMap<String, State>();
List<Object> handlersList = new ArrayList<Object>(1 + handlers.length);
handlersList.add(handler);
handlersList.addAll(Arrays.asList(handlers));
-
+
LinkedList<Field> fields = new LinkedList<Field>();
for (Object h : handlersList) {
fields.addAll(getFields(h instanceof Class ? (Class<?>) h : h.getClass()));
@@ -144,65 +156,99 @@ public class StateMachineFactory {
throw new StateMachineCreationException("Start state '" + start + "' not found.");
}
- setupTransitions(transitionAnnotation, transitionsAnnotation, states, handlersList);
+ setupTransitions(transitionAnnotation, transitionsAnnotation, entrySelfTransitionsAnnotation,
+ exitSelfTransitionsAnnotation, states, handlersList);
return new StateMachine(states.values(), start);
}
- private static void setupTransitions(Class<? extends Annotation> transitionAnnotation,
- Class<? extends Annotation> transitionsAnnotation, Map<String, State> states, List<Object> handlers) {
+ private static void setupTransitions(Class<? extends Annotation> transitionAnnotation,
+ Class<? extends Annotation> transitionsAnnotation,
+ Class<? extends Annotation> onEntrySelfTransitionAnnotation,
+ Class<? extends Annotation> onExitSelfTransitionAnnotation, Map<String, State> states, List<Object> handlers) {
for (Object handler : handlers) {
- setupTransitions(transitionAnnotation, transitionsAnnotation, states, handler);
+ setupTransitions(transitionAnnotation, transitionsAnnotation, onEntrySelfTransitionAnnotation,
+ onExitSelfTransitionAnnotation, states, handler);
+ }
+ }
+
+ private static void setupSelfTransitions(Method m, Class<? extends Annotation> onEntrySelfTransitionAnnotation,
+ Class<? extends Annotation> onExitSelfTransitionAnnotation, Map<String, State> states, Object handler) {
+ if (m.isAnnotationPresent(OnEntry.class)) {
+ OnEntry onEntryAnnotation = (OnEntry) m.getAnnotation(onEntrySelfTransitionAnnotation);
+ State state = states.get(onEntryAnnotation.value());
+ if (state == null) {
+ throw new StateMachineCreationException("Error encountered "
+ + "when processing onEntry annotation in method " + m + ". state " + onEntryAnnotation.value()
+ + " not Found.");
+
+ }
+ state.addOnEntrySelfTransaction(new MethodSelfTransition(m, handler));
}
+
+ if (m.isAnnotationPresent(OnExit.class)) {
+ OnExit onExitAnnotation = (OnExit) m.getAnnotation(onExitSelfTransitionAnnotation);
+ State state = states.get(onExitAnnotation.value());
+ if (state == null) {
+ throw new StateMachineCreationException("Error encountered "
+ + "when processing onExit annotation in method " + m + ". state " + onExitAnnotation.value()
+ + " not Found.");
+
+ }
+ state.addOnExitSelfTransaction(new MethodSelfTransition(m, handler));
+ }
+
}
-
- private static void setupTransitions(Class<? extends Annotation> transitionAnnotation,
- Class<? extends Annotation> transitionsAnnotation, Map<String, State> states, Object handler) {
-
+
+ private static void setupTransitions(Class<? extends Annotation> transitionAnnotation,
+ Class<? extends Annotation> transitionsAnnotation,
+ Class<? extends Annotation> onEntrySelfTransitionAnnotation,
+ Class<? extends Annotation> onExitSelfTransitionAnnotation, Map<String, State> states, Object handler) {
+
Method[] methods = handler.getClass().getDeclaredMethods();
Arrays.sort(methods, new Comparator<Method>() {
public int compare(Method m1, Method m2) {
return m1.toString().compareTo(m2.toString());
}
});
-
+
for (Method m : methods) {
+ setupSelfTransitions(m, onEntrySelfTransitionAnnotation, onExitSelfTransitionAnnotation, states, handler);
+
List<TransitionWrapper> transitionAnnotations = new ArrayList<TransitionWrapper>();
if (m.isAnnotationPresent(transitionAnnotation)) {
- transitionAnnotations.add(new TransitionWrapper(transitionAnnotation, m.getAnnotation(transitionAnnotation)));
+ transitionAnnotations.add(new TransitionWrapper(transitionAnnotation, m
+ .getAnnotation(transitionAnnotation)));
}
if (m.isAnnotationPresent(transitionsAnnotation)) {
- transitionAnnotations.addAll(Arrays.asList(new TransitionsWrapper(transitionAnnotation,
+ transitionAnnotations.addAll(Arrays.asList(new TransitionsWrapper(transitionAnnotation,
transitionsAnnotation, m.getAnnotation(transitionsAnnotation)).value()));
}
-
+
if (transitionAnnotations.isEmpty()) {
continue;
}
-
+
for (TransitionWrapper annotation : transitionAnnotations) {
Object[] eventIds = annotation.on();
if (eventIds.length == 0) {
- throw new StateMachineCreationException("Error encountered "
- + "when processing method " + m
+ throw new StateMachineCreationException("Error encountered " + "when processing method " + m
+ ". No event ids specified.");
}
if (annotation.in().length == 0) {
- throw new StateMachineCreationException("Error encountered "
- + "when processing method " + m
+ throw new StateMachineCreationException("Error encountered " + "when processing method " + m
+ ". No states specified.");
}
-
+
State next = null;
if (!annotation.next().equals(Transition.SELF)) {
next = states.get(annotation.next());
if (next == null) {
- throw new StateMachineCreationException("Error encountered "
- + "when processing method " + m
+ throw new StateMachineCreationException("Error encountered " + "when processing method " + m
+ ". Unknown next state: " + annotation.next() + ".");
}
}
-
+
for (Object event : eventIds) {
if (event == null) {
event = Event.WILDCARD_EVENT_ID;
@@ -213,8 +259,7 @@ public class StateMachineFactory {
for (String in : annotation.in()) {
State state = states.get(in);
if (state == null) {
- throw new StateMachineCreationException("Error encountered "
- + "when processing method "
+ throw new StateMachineCreationException("Error encountered " + "when processing method "
+ m + ". Unknown state: " + in + ".");
}
@@ -233,14 +278,10 @@ public class StateMachineFactory {
continue;
}
- if ((f.getModifiers() & Modifier.STATIC) == 0
- || (f.getModifiers() & Modifier.FINAL) == 0
+ if ((f.getModifiers() & Modifier.STATIC) == 0 || (f.getModifiers() & Modifier.FINAL) == 0
|| !f.getType().equals(String.class)) {
- throw new StateMachineCreationException("Error encountered when "
- + "processing field " + f
- + ". Only static final "
- + "String fields can be used with the @State "
- + "annotation.");
+ throw new StateMachineCreationException("Error encountered when " + "processing field " + f
+ + ". Only static final " + "String fields can be used with the @State " + "annotation.");
}
if (!f.isAccessible()) {
@@ -252,7 +293,7 @@ public class StateMachineFactory {
return fields;
}
-
+
static State[] createStates(List<Field> fields) {
LinkedHashMap<String, State> states = new LinkedHashMap<String, State>();
@@ -266,8 +307,8 @@ public class StateMachineFactory {
try {
value = (String) f.get(null);
} catch (IllegalAccessException iae) {
- throw new StateMachineCreationException("Error encountered when "
- + "processing field " + f + ".", iae);
+ throw new StateMachineCreationException("Error encountered when " + "processing field " + f + ".",
+ iae);
}
org.apache.mina.statemachine.annotation.State stateAnnotation = f
@@ -284,38 +325,44 @@ public class StateMachineFactory {
}
/*
- * If no new states were added to states during this iteration it
+ * If no new states were added to states during this iteration it
* means that all fields in fields specify non-existent parents.
*/
if (states.size() == numStates) {
throw new StateMachineCreationException("Error encountered while creating "
- + "FSM. The following fields specify non-existing "
- + "parent states: " + fields);
+ + "FSM. The following fields specify non-existing " + "parent states: " + fields);
}
}
return states.values().toArray(new State[0]);
}
-
+
private static class TransitionWrapper {
private final Class<? extends Annotation> transitionClazz;
+
private final Annotation annotation;
+
public TransitionWrapper(Class<? extends Annotation> transitionClazz, Annotation annotation) {
this.transitionClazz = transitionClazz;
this.annotation = annotation;
}
+
Object[] on() {
return getParameter("on", Object[].class);
}
+
String[] in() {
return getParameter("in", String[].class);
}
+
String next() {
return getParameter("next", String.class);
}
+
int weight() {
return getParameter("weight", Integer.TYPE);
}
+
@SuppressWarnings("unchecked")
private <T> T getParameter(String name, Class<T> returnType) {
try {
@@ -325,22 +372,26 @@ public class StateMachineFactory {
}
return (T) m.invoke(annotation);
} catch (Throwable t) {
- throw new StateMachineCreationException("Could not get parameter '"
- + name + "' from Transition annotation " + transitionClazz);
+ throw new StateMachineCreationException("Could not get parameter '" + name
+ + "' from Transition annotation " + transitionClazz);
}
}
}
-
+
private static class TransitionsWrapper {
private final Class<? extends Annotation> transitionsclazz;
+
private final Class<? extends Annotation> transitionClazz;
+
private final Annotation annotation;
- public TransitionsWrapper(Class<? extends Annotation> transitionClazz,
+
+ public TransitionsWrapper(Class<? extends Annotation> transitionClazz,
Class<? extends Annotation> transitionsclazz, Annotation annotation) {
this.transitionClazz = transitionClazz;
this.transitionsclazz = transitionsclazz;
this.annotation = annotation;
}
+
TransitionWrapper[] value() {
Annotation[] annos = getParameter("value", Annotation[].class);
TransitionWrapper[] wrappers = new TransitionWrapper[annos.length];
@@ -349,6 +400,7 @@ public class StateMachineFactory {
}
return wrappers;
}
+
@SuppressWarnings("unchecked")
private <T> T getParameter(String name, Class<T> returnType) {
try {
@@ -358,8 +410,8 @@ public class StateMachineFactory {
}
return (T) m.invoke(annotation);
} catch (Throwable t) {
- throw new StateMachineCreationException("Could not get parameter '"
- + name + "' from Transitions annotation " + transitionsclazz);
+ throw new StateMachineCreationException("Could not get parameter '" + name
+ + "' from Transitions annotation " + transitionsclazz);
}
}
}
Added: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnEntry.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnEntry.java?rev=1359127&view=auto
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnEntry.java (added)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnEntry.java Mon Jul 9 12:54:07 2012
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.statemachine.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used on methods to indicate that the method will be executed
+ * before entering a certain state
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface OnEntry {
+ /**
+ * Sets the id of related state.
+ */
+ String value();
+}
Added: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnExit.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnExit.java?rev=1359127&view=auto
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnExit.java (added)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/OnExit.java Mon Jul 9 12:54:07 2012
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.statemachine.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used on methods to indicate that the method will be executed
+ * before existing from a certain state
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface OnExit {
+ /**
+ * Sets the id of related state.
+ */
+ String value();
+}
Modified: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/TransitionAnnotation.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/TransitionAnnotation.java?rev=1359127&r1=1359126&r2=1359127&view=diff
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/TransitionAnnotation.java (original)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/annotation/TransitionAnnotation.java Mon Jul 9 12:54:07 2012
@@ -27,7 +27,7 @@ import java.lang.annotation.Target;
/**
* Annotation used to mark other annotations as being transition annotations.
- * The annotation used to group transition annotations must be given as
+ * The annotation used to group transition annotations must be given as
* parameter.
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
Added: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/AbstractSelfTransition.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/AbstractSelfTransition.java?rev=1359127&view=auto
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/AbstractSelfTransition.java (added)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/AbstractSelfTransition.java Mon Jul 9 12:54:07 2012
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.statemachine.transition;
+
+import org.apache.mina.statemachine.context.StateContext;
+import org.apache.mina.statemachine.State;
+
+/**
+ * Abstract {@link SelfTransition} implementation.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+
+public abstract class AbstractSelfTransition implements SelfTransition {
+
+ /**
+ * Creates a new instance
+ *
+ */
+ public AbstractSelfTransition() {
+
+ }
+
+ /**
+ * Executes this {@link SelfTransition}.
+ *
+ * @return <code>true</code> if the {@link SelfTransition} has been executed
+ * successfully
+ */
+ protected abstract boolean doExecute(StateContext stateContext, State state);
+
+ public boolean execute(StateContext stateContext, State state) {
+
+ return doExecute(stateContext, state);
+ }
+
+}
Added: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/MethodSelfTransition.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/MethodSelfTransition.java?rev=1359127&view=auto
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/MethodSelfTransition.java (added)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/MethodSelfTransition.java Mon Jul 9 12:54:07 2012
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.statemachine.transition;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+import org.apache.mina.statemachine.context.StateContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.mina.statemachine.State;
+
+/**
+ * {@link SelfTransition} which invokes a {@link Method}. The {@link Method} can
+ * have zero or any number of StateContext and State regarding order
+ * <p>
+ * Normally you wouldn't create instances of this class directly but rather use the
+ * {@link SelfTransition} annotation to define the methods which should be used as
+ * transitions in your state machine and then let {@link StateMachineFactory} create a
+ * {@link StateMachine} for you.
+ * </p>
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public class MethodSelfTransition extends AbstractSelfTransition {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MethodTransition.class);
+
+ private Method method;
+
+ private final Object target;
+
+ private static final Object[] EMPTY_ARGUMENTS = new Object[0];
+
+ public MethodSelfTransition(Method method, Object target) {
+ super();
+ this.method = method;
+ this.target = target;
+ }
+
+ /**
+ * Creates a new instance
+ *
+ * @param method the target method.
+ * @param target the target object.
+ */
+ public MethodSelfTransition(String methodName, Object target) {
+
+ this.target = target;
+
+ Method[] candidates = target.getClass().getMethods();
+ Method result = null;
+ for (int i = 0; i < candidates.length; i++) {
+ if (candidates[i].getName().equals(methodName)) {
+ if (result != null) {
+ throw new AmbiguousMethodException(methodName);
+ }
+ result = candidates[i];
+ }
+ }
+
+ if (result == null) {
+ throw new NoSuchMethodException(methodName);
+ }
+
+ this.method = result;
+
+ }
+
+ /**
+ * Returns the target {@link Method}.
+ *
+ * @return the method.
+ */
+ public Method getMethod() {
+ return method;
+ }
+
+ public boolean doExecute(StateContext stateContext, State state) {
+ Class<?>[] types = method.getParameterTypes();
+
+ if (types.length == 0) {
+ invokeMethod(EMPTY_ARGUMENTS);
+ return true;
+ }
+
+ if (types.length > 2) {
+ return false;
+ }
+
+ Object[] args = new Object[types.length];
+
+ int i = 0;
+ if (types[i].isAssignableFrom(StateContext.class)) {
+ args[i++] = stateContext;
+ }
+ if (i < types.length && types[i].isAssignableFrom(State.class)) {
+ args[i++] = state;
+ }
+
+ invokeMethod(args);
+
+ return true;
+ }
+
+ private void invokeMethod(Object[] arguments) {
+ try {
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("Executing method " + method + " with arguments " + Arrays.asList(arguments));
+ }
+ method.invoke(target, arguments);
+ } catch (InvocationTargetException ite) {
+ if (ite.getCause() instanceof RuntimeException) {
+ throw (RuntimeException) ite.getCause();
+ }
+ throw new MethodInvocationException(method, ite);
+ } catch (IllegalAccessException iae) {
+ throw new MethodInvocationException(method, iae);
+ }
+ }
+
+}
Added: mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/SelfTransition.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/SelfTransition.java?rev=1359127&view=auto
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/SelfTransition.java (added)
+++ mina/branches/2.0/mina-statemachine/src/main/java/org/apache/mina/statemachine/transition/SelfTransition.java Mon Jul 9 12:54:07 2012
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.statemachine.transition;
+
+import org.apache.mina.statemachine.context.StateContext;
+import org.apache.mina.statemachine.State;
+
+/**
+ * The interface implemented by classes which need to react on entering
+ * a certain states.
+ *
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ */
+public interface SelfTransition {
+ /**
+ * Executes this {@link SelfTransition}.
+ *
+ * @return <code>true</code> if the {@link SelfTransition} was executed,
+ * <code>false</code> otherwise.
+ */
+
+ boolean execute(StateContext stateContext, State state);
+
+}
Modified: mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineProxyBuilderTest.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineProxyBuilderTest.java?rev=1359127&r1=1359126&r2=1359127&view=diff
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineProxyBuilderTest.java (original)
+++ mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineProxyBuilderTest.java Mon Jul 9 12:54:07 2012
@@ -26,7 +26,11 @@ import java.util.LinkedList;
import org.apache.mina.statemachine.annotation.Transition;
import org.apache.mina.statemachine.annotation.Transitions;
+import org.apache.mina.statemachine.annotation.OnEntry;
+import org.apache.mina.statemachine.annotation.OnExit;
+import org.apache.mina.statemachine.context.StateContext;
import org.apache.mina.statemachine.event.Event;
+import org.apache.mina.statemachine.transition.MethodSelfTransition;
import org.apache.mina.statemachine.transition.MethodTransition;
import org.junit.Test;
@@ -53,7 +57,7 @@ public class StateMachineProxyBuilderTes
reentrant.call1(reentrant);
assertTrue(handler.finished);
}
-
+
@Test
public void testTapeDeckStateMachine() throws Exception {
TapeDeckStateMachineHandler handler = new TapeDeckStateMachineHandler();
@@ -73,6 +77,15 @@ public class StateMachineProxyBuilderTes
s4.addTransition(new MethodTransition("eject", s1, "ejected", handler));
s5.addTransition(new MethodTransition("pause", s3, "playing", handler));
+ s2.addOnEntrySelfTransaction(new MethodSelfTransition("onEntryS2", handler));
+ s2.addOnExitSelfTransaction(new MethodSelfTransition("onExitS2", handler));
+
+ s3.addOnEntrySelfTransaction(new MethodSelfTransition("onEntryS3", handler));
+ s3.addOnExitSelfTransaction(new MethodSelfTransition("onExitS3", handler));
+
+ s4.addOnEntrySelfTransaction(new MethodSelfTransition("onEntryS4", handler));
+ s4.addOnExitSelfTransaction(new MethodSelfTransition("onExitS4", handler));
+
StateMachine sm = new StateMachine(new State[] { s1, s2, s3, s4, s5 }, "s1");
TapeDeck player = new StateMachineProxyBuilder().create(TapeDeck.class, sm);
player.insert("Kings of convenience - Riot on an empty street");
@@ -85,20 +98,30 @@ public class StateMachineProxyBuilderTes
LinkedList<String> messages = handler.messages;
assertEquals("Tape 'Kings of convenience - Riot on an empty street' inserted", messages.removeFirst());
+ assertEquals("S2 entered", messages.removeFirst());
assertEquals("Playing", messages.removeFirst());
+ assertEquals("S2 exited", messages.removeFirst());
+ assertEquals("S3 entered with stateContext", messages.removeFirst());
assertEquals("Paused", messages.removeFirst());
+ assertEquals("S3 exited with stateContext", messages.removeFirst());
assertEquals("Playing", messages.removeFirst());
+ assertEquals("S3 entered with stateContext", messages.removeFirst());
assertEquals("Error: Cannot eject at this time", messages.removeFirst());
assertEquals("Stopped", messages.removeFirst());
+ assertEquals("S3 exited with stateContext", messages.removeFirst());
+ assertEquals("S4 entered with stateContext and state", messages.removeFirst());
assertEquals("Tape ejected", messages.removeFirst());
+ assertEquals("S4 exited with stateContext and state", messages.removeFirst());
+
assertTrue(messages.isEmpty());
}
-
+
@Test
public void testTapeDeckStateMachineAnnotations() throws Exception {
TapeDeckStateMachineHandler handler = new TapeDeckStateMachineHandler();
- StateMachine sm = StateMachineFactory.getInstance(Transition.class).create(TapeDeckStateMachineHandler.S1, handler);
+ StateMachine sm = StateMachineFactory.getInstance(Transition.class).create(TapeDeckStateMachineHandler.S1,
+ handler);
TapeDeck player = new StateMachineProxyBuilder().create(TapeDeck.class, sm);
player.insert("Kings of convenience - Riot on an empty street");
@@ -111,18 +134,29 @@ public class StateMachineProxyBuilderTes
LinkedList<String> messages = handler.messages;
assertEquals("Tape 'Kings of convenience - Riot on an empty street' inserted", messages.removeFirst());
+ assertEquals("S2 entered", messages.removeFirst());
assertEquals("Playing", messages.removeFirst());
+ assertEquals("S2 exited", messages.removeFirst());
+ assertEquals("S3 entered with stateContext", messages.removeFirst());
assertEquals("Paused", messages.removeFirst());
+ assertEquals("S3 exited with stateContext", messages.removeFirst());
assertEquals("Playing", messages.removeFirst());
+ assertEquals("S3 entered with stateContext", messages.removeFirst());
assertEquals("Error: Cannot eject at this time", messages.removeFirst());
assertEquals("Stopped", messages.removeFirst());
+ assertEquals("S3 exited with stateContext", messages.removeFirst());
+ assertEquals("S4 entered with stateContext and state", messages.removeFirst());
assertEquals("Tape ejected", messages.removeFirst());
+ assertEquals("S4 exited with stateContext and state", messages.removeFirst());
+
assertTrue(messages.isEmpty());
}
-
+
public interface Reentrant {
void call1(Reentrant proxy);
+
void call2(Reentrant proxy);
+
void call3(Reentrant proxy);
}
@@ -144,22 +178,67 @@ public class StateMachineProxyBuilderTes
public interface TapeDeck {
void insert(String name);
+
void eject();
+
void start();
+
void pause();
+
void stop();
}
-
+
public static class TapeDeckStateMachineHandler {
- @org.apache.mina.statemachine.annotation.State public static final String PARENT = "parent";
- @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S1 = "s1";
- @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S2 = "s2";
- @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S3 = "s3";
- @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S4 = "s4";
- @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S5 = "s5";
-
+ @org.apache.mina.statemachine.annotation.State
+ public static final String PARENT = "parent";
+
+ @org.apache.mina.statemachine.annotation.State(PARENT)
+ public static final String S1 = "s1";
+
+ @org.apache.mina.statemachine.annotation.State(PARENT)
+ public static final String S2 = "s2";
+
+ @org.apache.mina.statemachine.annotation.State(PARENT)
+ public static final String S3 = "s3";
+
+ @org.apache.mina.statemachine.annotation.State(PARENT)
+ public static final String S4 = "s4";
+
+ @org.apache.mina.statemachine.annotation.State(PARENT)
+ public static final String S5 = "s5";
+
private LinkedList<String> messages = new LinkedList<String>();
-
+
+ @OnEntry(S2)
+ public void onEntryS2() {
+ messages.add("S2 entered");
+ }
+
+ @OnExit(S2)
+ public void onExitS2() {
+ messages.add("S2 exited");
+ }
+
+ @OnEntry(S3)
+ public void onEntryS3(StateContext stateContext) {
+ messages.add("S3 entered with stateContext");
+ }
+
+ @OnExit(S3)
+ public void onExitS3(StateContext stateContext) {
+ messages.add("S3 exited with stateContext");
+ }
+
+ @OnEntry(S4)
+ public void onEntryS4(StateContext stateContext, State state) {
+ messages.add("S4 entered with stateContext and state");
+ }
+
+ @OnExit(S4)
+ public void onExitS4(StateContext stateContext, State state) {
+ messages.add("S4 exited with stateContext and state");
+ }
+
@Transition(on = "insert", in = "s1", next = "s2")
public void inserted(String name) {
messages.add("Tape '" + name + "' inserted");
@@ -169,13 +248,13 @@ public class StateMachineProxyBuilderTes
public void ejected() {
messages.add("Tape ejected");
}
-
- @Transitions({@Transition( on = "start", in = "s2", next = "s3" ),
- @Transition( on = "pause", in = "s5", next = "s3" )})
+
+ @Transitions({ @Transition(on = "start", in = "s2", next = "s3"),
+ @Transition(on = "pause", in = "s5", next = "s3") })
public void playing() {
messages.add("Playing");
}
-
+
@Transition(on = "pause", in = "s3", next = "s5")
public void paused() {
messages.add("Paused");
Modified: mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineTest.java
URL: http://svn.apache.org/viewvc/mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineTest.java?rev=1359127&r1=1359126&r2=1359127&view=diff
==============================================================================
--- mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineTest.java (original)
+++ mina/branches/2.0/mina-statemachine/src/test/java/org/apache/mina/statemachine/StateMachineTest.java Mon Jul 9 12:54:07 2012
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertSam
import org.apache.mina.statemachine.context.DefaultStateContext;
import org.apache.mina.statemachine.context.StateContext;
import org.apache.mina.statemachine.event.Event;
+import org.apache.mina.statemachine.transition.AbstractSelfTransition;
import org.apache.mina.statemachine.transition.AbstractTransition;
import org.junit.Test;
@@ -146,4 +147,40 @@ public class StateMachineTest {
return true;
}
}
+
+ private static class SampleSelfTransition extends AbstractSelfTransition {
+ @SuppressWarnings("unused")
+ public SampleSelfTransition() {
+ super();
+ }
+
+
+ @Override
+ protected boolean doExecute(StateContext stateContext, State state) {
+ stateContext.setAttribute("SelfSuccess" + state.getId(), true);
+ return true;
+ }
+
+ }
+
+
+ @Test
+ public void testOnEntry() throws Exception {
+ State s1 = new State("s1");
+ State s2 = new State("s2");
+
+ s1.addTransition(new SuccessTransition("foo", s2));
+ s1.addOnExitSelfTransaction(new SampleSelfTransition());
+ s2.addOnEntrySelfTransaction(new SampleSelfTransition());
+
+ StateContext context = new DefaultStateContext();
+ StateMachine sm = new StateMachine(new State[] { s1, s2 }, "s1");
+ sm.handle(new Event("foo", context));
+ assertEquals(true, context.getAttribute("success"));
+ assertEquals(true, context.getAttribute("SelfSuccess" + s1.getId()));
+ assertEquals(true, context.getAttribute("SelfSuccess" + s2.getId()));
+
+ }
+
+
}