001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.example.tapedeck;
021
022import static org.apache.mina.statemachine.event.IoHandlerEvents.*;
023
024import org.apache.mina.core.future.IoFutureListener;
025import org.apache.mina.core.session.IoSession;
026import org.apache.mina.statemachine.StateControl;
027import org.apache.mina.statemachine.annotation.IoHandlerTransition;
028import org.apache.mina.statemachine.annotation.IoHandlerTransitions;
029import org.apache.mina.statemachine.annotation.State;
030import org.apache.mina.statemachine.context.AbstractStateContext;
031import org.apache.mina.statemachine.context.StateContext;
032import org.apache.mina.statemachine.event.Event;
033
034/**
035 * The actual state machine implementation for the tape deck server.
036 *
037 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
038 */
039public class TapeDeckServer {
040    @State public static final String ROOT = "Root";
041    @State(ROOT) public static final String EMPTY = "Empty";
042    @State(ROOT) public static final String LOADED = "Loaded";
043    @State(ROOT) public static final String PLAYING = "Playing";
044    @State(ROOT) public static final String PAUSED = "Paused";
045    
046    private final String[] tapes = {
047            "The Knife - Silent Shout", 
048            "Kings of convenience - Riot on an empty street"
049    };
050    
051    static class TapeDeckContext extends AbstractStateContext {
052        private String tapeName;
053    }
054    
055    @IoHandlerTransition(on = SESSION_OPENED, in = EMPTY)
056    public void connect(IoSession session) {
057        session.write("+ Greetings from your tape deck!");
058    }
059    
060    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = EMPTY, next = LOADED)
061    public void loadTape(TapeDeckContext context, IoSession session, LoadCommand cmd) {
062        if (cmd.getTapeNumber() < 1 || cmd.getTapeNumber() > tapes.length) {
063            session.write("- Unknown tape number: " + cmd.getTapeNumber());
064            StateControl.breakAndGotoNext(EMPTY);
065        } else {
066            context.tapeName = tapes[cmd.getTapeNumber() - 1];
067            session.write("+ \"" + context.tapeName + "\" loaded");
068        }
069    }
070
071    @IoHandlerTransitions({
072        @IoHandlerTransition(on = MESSAGE_RECEIVED, in = LOADED, next = PLAYING),
073        @IoHandlerTransition(on = MESSAGE_RECEIVED, in = PAUSED, next = PLAYING)
074    })
075    public void playTape(TapeDeckContext context, IoSession session, PlayCommand cmd) {
076        session.write("+ Playing \"" + context.tapeName + "\"");
077    }
078    
079    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = PLAYING, next = PAUSED)
080    public void pauseTape(TapeDeckContext context, IoSession session, PauseCommand cmd) {
081        session.write("+ \"" + context.tapeName + "\" paused");
082    }
083    
084    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = PLAYING, next = LOADED)
085    public void stopTape(TapeDeckContext context, IoSession session, StopCommand cmd) {
086        session.write("+ \"" + context.tapeName + "\" stopped");
087    }
088    
089    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = LOADED, next = EMPTY)
090    public void ejectTape(TapeDeckContext context, IoSession session, EjectCommand cmd) {
091        session.write("+ \"" + context.tapeName + "\" ejected");
092        context.tapeName = null;
093    }
094    
095    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = ROOT)
096    public void listTapes(IoSession session, ListCommand cmd) {
097        StringBuilder response = new StringBuilder("+ (");
098        for (int i = 0; i < tapes.length; i++) {
099            response.append(i + 1).append(": ");
100            response.append('"').append(tapes[i]).append('"');
101            if (i < tapes.length - 1) {
102                response.append(", ");
103            }
104        }
105        response.append(')');
106        session.write(response);
107    }
108    
109    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = ROOT)
110    public void info(TapeDeckContext context, IoSession session, InfoCommand cmd) {
111        String state = context.getCurrentState().getId().toLowerCase();
112        if (context.tapeName == null) {
113            session.write("+ Tape deck is " + state + "");
114        } else {
115            session.write("+ Tape deck is " + state 
116                    + ". Current tape: \"" + context.tapeName + "\"");
117        }
118    }
119    
120    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = ROOT)
121    public void quit(TapeDeckContext context, IoSession session, QuitCommand cmd) {
122        session.write("+ Bye! Please come back!").addListener(IoFutureListener.CLOSE);
123    }
124    
125    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = ROOT, weight = 10)
126    public void error(Event event, StateContext context, IoSession session, Command cmd) {
127        session.write("- Cannot " + cmd.getName() 
128                + " while " + context.getCurrentState().getId().toLowerCase());
129    }
130    
131    @IoHandlerTransition(on = EXCEPTION_CAUGHT, in = ROOT)
132    public void commandSyntaxError(IoSession session, CommandSyntaxException e) {
133        session.write("- " + e.getMessage());
134    }
135    
136    @IoHandlerTransition(on = EXCEPTION_CAUGHT, in = ROOT, weight = 10)
137    public void exceptionCaught(IoSession session, Exception e) {
138        e.printStackTrace();
139        session.close(true);
140    }
141    
142    @IoHandlerTransition(in = ROOT, weight = 100)
143    public void unhandledEvent() {
144    }
145    
146}