blob: 84f5641b797f74d96387bec145163fc7bde12803 [file] [log] [blame]
/*
* 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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
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;
/**
* Tests {@link StateMachineProxyBuilder}.
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class StateMachineProxyBuilderTest {
@Test
public void testReentrantStateMachine() throws Exception {
ReentrantStateMachineHandler handler = new ReentrantStateMachineHandler();
State s1 = new State("s1");
State s2 = new State("s2");
State s3 = new State("s3");
s1.addTransition(new MethodTransition("call1", s2, handler));
s2.addTransition(new MethodTransition("call2", s3, handler));
s3.addTransition(new MethodTransition("call3", handler));
StateMachine sm = new StateMachine(new State[] { s1, s2, s3 }, "s1");
Reentrant reentrant = new StateMachineProxyBuilder().create(Reentrant.class, sm);
reentrant.call1(reentrant);
assertTrue(handler.finished);
}
@Test
public void testTapeDeckStateMachine() throws Exception {
TapeDeckStateMachineHandler handler = new TapeDeckStateMachineHandler();
State parent = new State("parent");
State s1 = new State("s1", parent);
State s2 = new State("s2", parent);
State s3 = new State("s3", parent);
State s4 = new State("s4", parent);
State s5 = new State("s5", parent);
parent.addTransition(new MethodTransition("*", "error", handler));
s1.addTransition(new MethodTransition("insert", s2, "inserted", handler));
s2.addTransition(new MethodTransition("start", s3, "playing", handler));
s3.addTransition(new MethodTransition("stop", s4, "stopped", handler));
s3.addTransition(new MethodTransition("pause", s5, "paused", handler));
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");
player.start();
player.pause();
player.pause();
player.eject();
player.stop();
player.eject();
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);
TapeDeck player = new StateMachineProxyBuilder().create(TapeDeck.class, sm);
player.insert("Kings of convenience - Riot on an empty street");
player.start();
player.pause();
player.pause();
player.eject();
player.stop();
player.eject();
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);
}
public static class ReentrantStateMachineHandler {
private boolean finished = false;
public void call1(Reentrant proxy) {
proxy.call2(proxy);
}
public void call2(Reentrant proxy) {
proxy.call3(proxy);
}
public void call3(Reentrant proxy) {
finished = true;
}
}
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";
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");
}
@Transition(on = "eject", in = "s4", next = "s1")
public void ejected() {
messages.add("Tape ejected");
}
@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");
}
@Transition(on = "stop", in = "s3", next = "s4")
public void stopped() {
messages.add("Stopped");
}
@Transition(on = "*", in = "parent")
public void error(Event event) {
messages.add("Error: Cannot " + event.getId() + " at this time");
}
}
}