1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.statemachine;
21  
22  import java.util.LinkedList;
23  
24  import junit.framework.TestCase;
25  
26  import org.apache.mina.statemachine.annotation.Transition;
27  import org.apache.mina.statemachine.annotation.Transitions;
28  import org.apache.mina.statemachine.event.Event;
29  import org.apache.mina.statemachine.transition.MethodTransition;
30  
31  /**
32   * Tests {@link StateMachineProxyBuilder}.
33   *
34   * @author The Apache MINA Project (dev@mina.apache.org)
35   * @version $Rev: 641052 $, $Date: 2008-03-25 23:22:35 +0100 (Tue, 25 Mar 2008) $
36   */
37  public class StateMachineProxyBuilderTest extends TestCase {
38  
39      public void testReentrantStateMachine() throws Exception {
40          ReentrantStateMachineHandler handler = new ReentrantStateMachineHandler();
41  
42          State s1 = new State("s1");
43          State s2 = new State("s2");
44          State s3 = new State("s3");
45  
46          s1.addTransition(new MethodTransition("call1", s2, handler));
47          s2.addTransition(new MethodTransition("call2", s3, handler));
48          s3.addTransition(new MethodTransition("call3", handler));
49  
50          StateMachine sm = new StateMachine(new State[] { s1, s2, s3 }, "s1");
51          Reentrant reentrant = new StateMachineProxyBuilder().create(Reentrant.class, sm);
52          reentrant.call1(reentrant);
53          assertTrue(handler.finished);
54      }
55      
56      public void testTapeDeckStateMachine() throws Exception {
57          TapeDeckStateMachineHandler handler = new TapeDeckStateMachineHandler();
58  
59          State parent = new State("parent");
60          State s1 = new State("s1", parent);
61          State s2 = new State("s2", parent);
62          State s3 = new State("s3", parent);
63          State s4 = new State("s4", parent);
64          State s5 = new State("s5", parent);
65  
66          parent.addTransition(new MethodTransition("*", "error", handler));
67          s1.addTransition(new MethodTransition("insert", s2, "inserted", handler));
68          s2.addTransition(new MethodTransition("start", s3, "playing", handler));
69          s3.addTransition(new MethodTransition("stop", s4, "stopped", handler));
70          s3.addTransition(new MethodTransition("pause", s5, "paused", handler));
71          s4.addTransition(new MethodTransition("eject", s1, "ejected", handler));
72          s5.addTransition(new MethodTransition("pause", s3, "playing", handler));
73  
74          StateMachine sm = new StateMachine(new State[] { s1, s2, s3, s4, s5 }, "s1");
75          TapeDeck player = new StateMachineProxyBuilder().create(TapeDeck.class, sm);
76          player.insert("Kings of convenience - Riot on an empty street");
77          player.start();
78          player.pause();
79          player.pause();
80          player.eject();
81          player.stop();
82          player.eject();
83  
84          LinkedList<String> messages = handler.messages;
85          assertEquals("Tape 'Kings of convenience - Riot on an empty street' inserted", messages.removeFirst());
86          assertEquals("Playing", messages.removeFirst());
87          assertEquals("Paused", messages.removeFirst());
88          assertEquals("Playing", messages.removeFirst());
89          assertEquals("Error: Cannot eject at this time", messages.removeFirst());
90          assertEquals("Stopped", messages.removeFirst());
91          assertEquals("Tape ejected", messages.removeFirst());
92          assertTrue(messages.isEmpty());
93      }
94      
95      public void testTapeDeckStateMachineAnnotations() throws Exception {
96          TapeDeckStateMachineHandler handler = new TapeDeckStateMachineHandler();
97  
98          StateMachine sm = StateMachineFactory.getInstance(Transition.class).create(TapeDeckStateMachineHandler.S1, handler);
99  
100         TapeDeck player = new StateMachineProxyBuilder().create(TapeDeck.class, sm);
101         player.insert("Kings of convenience - Riot on an empty street");
102         player.start();
103         player.pause();
104         player.pause();
105         player.eject();
106         player.stop();
107         player.eject();
108 
109         LinkedList<String> messages = handler.messages;
110         assertEquals("Tape 'Kings of convenience - Riot on an empty street' inserted", messages.removeFirst());
111         assertEquals("Playing", messages.removeFirst());
112         assertEquals("Paused", messages.removeFirst());
113         assertEquals("Playing", messages.removeFirst());
114         assertEquals("Error: Cannot eject at this time", messages.removeFirst());
115         assertEquals("Stopped", messages.removeFirst());
116         assertEquals("Tape ejected", messages.removeFirst());
117         assertTrue(messages.isEmpty());
118     }
119     
120     public interface Reentrant {
121         void call1(Reentrant proxy);
122         void call2(Reentrant proxy);
123         void call3(Reentrant proxy);
124     }
125 
126     public static class ReentrantStateMachineHandler {
127         private boolean finished = false;
128 
129         public void call1(Reentrant proxy) {
130             proxy.call2(proxy);
131         }
132 
133         public void call2(Reentrant proxy) {
134             proxy.call3(proxy);
135         }
136 
137         public void call3(
138                 @SuppressWarnings("unused") Reentrant proxy) {
139             finished = true;
140         }
141     }
142 
143     public interface TapeDeck {
144         void insert(String name);
145         void eject();
146         void start();
147         void pause();
148         void stop();
149     }
150     
151     public static class TapeDeckStateMachineHandler {
152         @org.apache.mina.statemachine.annotation.State public static final String PARENT = "parent";
153         @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S1 = "s1";
154         @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S2 = "s2";
155         @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S3 = "s3";
156         @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S4 = "s4";
157         @org.apache.mina.statemachine.annotation.State(PARENT) public static final String S5 = "s5";
158         
159         private LinkedList<String> messages = new LinkedList<String>();
160         
161         @Transition(on = "insert", in = "s1", next = "s2")
162         public void inserted(String name) {
163             messages.add("Tape '" + name + "' inserted");
164         }
165 
166         @Transition(on = "eject", in = "s4", next = "s1")
167         public void ejected() {
168             messages.add("Tape ejected");
169         }
170         
171         @Transitions({@Transition( on = "start", in = "s2", next = "s3" ),
172                    @Transition( on = "pause", in = "s5", next = "s3" )})
173         public void playing() {
174             messages.add("Playing");
175         }
176         
177         @Transition(on = "pause", in = "s3", next = "s5")
178         public void paused() {
179             messages.add("Paused");
180         }
181 
182         @Transition(on = "stop", in = "s3", next = "s4")
183         public void stopped() {
184             messages.add("Stopped");
185         }
186 
187         @Transition(on = "*", in = "parent")
188         public void error(Event event) {
189             messages.add("Error: Cannot " + event.getId() + " at this time");
190         }
191     };    
192 }