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}