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()));
+
+    }
+    
+
 }