apache mina 学习(十三)-----状态机和IoHander配合使用

原创 2012年03月21日 15:36:47

现在我们把上一张的收录机的例子改造为一个tcp服务器,用文本的传输,效果如下;

telnet localhost 12345
S: + Greetings from your tape deck!
C: list
S: + (1: "The Knife - Silent Shout", 2: "Kings of convenience - Riot on an empty street")
C: load 1
S: + "The Knife - Silent Shout" loaded
C: play
S: + Playing "The Knife - Silent Shout"
C: pause
S: + "The Knife - Silent Shout" paused
C: play
S: + Playing "The Knife - Silent Shout"
C: info
S: + Tape deck is playing. Current tape: "The Knife - Silent Shout"
C: eject
S: - Cannot eject while playing
C: stop
S: + "The Knife - Silent Shout" stopped
C: eject
S: + "The Knife - Silent Shout" ejected
C: quit
S: + Bye! Please come back!
完整的代码在org.apache.mina.example.tapedeck 包中
状态如下:
@State public static final String ROOT = "Root";
@State(ROOT) public static final String EMPTY = "Empty";
@State(ROOT) public static final String LOADED = "Loaded";
@State(ROOT) public static final String PLAYING = "Playing";
@State(ROOT) public static final String PAUSED = "Paused";
事件方法有些变化:
@IoHandlerTransitions({
    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = LOADED, next = PLAYING),
    @IoHandlerTransition(on = MESSAGE_RECEIVED, in = PAUSED, next = PLAYING)
})
public void playTape(TapeDeckContext context, IoSession session, PlayCommand cmd) {
    session.write("+ Playing \"" + context.tapeName + "\"");
}
我们没有使用上个例子中的Transaction注解,而是用了IoHandlerTransaction注解,当为Mina的IoHandler创建一个状态机时,它会选择让你使用Java enum (枚举)类型来替代我们上面使用的字符串类型。这个在Mina的IoFilter中也是一样的。我们现在使用MESSAGE_RECEIVED来替代"play"来作为事件的名字(on是@IoHandlerTransition的一个属性)。这个常量是在org.apache.mina.statemachine.event.IoHandlerEvents中定义的,它的值是"messageReceived",这个和Mina的IoHandler中的messageReceived()方法是一致的。同时我们自定义了一个StateContext状态上下文的实现TapeDeckContext,主要作用就是用于返回当前收录机的名字。
static class TapeDeckContext extends AbstractStateContext {
    public String tapeName;
}
playTape()方法使用了PlayCommand命令来作为它的最后的一个参数意味着只有在客户端发送的信息被编码成layCommand命令时,该方法才会被调用
@IoHandlerTransition(on = MESSAGE_RECEIVED, in = EMPTY, next = LOADED)
public void loadTape(TapeDeckContext context, IoSession session, LoadCommand cmd) {
    if (cmd.getTapeNumber() < 1 || cmd.getTapeNumber() > tapes.length) {
        session.write("- Unknown tape number: " + cmd.getTapeNumber());
        StateControl.breakAndGotoNext(EMPTY);//如果用户传递了非法的状态,则用empty代替
    } else {
        context.tapeName = tapes[cmd.getTapeNumber() - 1];
        session.write("+ \"" + context.tapeName + "\" loaded");
    }
}
connect()方法将会在Mina开启一个会话并调用sessionOpened()方法时触发
@IoHandlerTransition(on = SESSION_OPENED, in = EMPTY)
public void connect(IoSession session) {
    session.write("+ Greetings from your tape deck!");
}
它所做的工作就是向客户端发送欢迎的信息。状态机将会保持空的状态。pauseTape(), stopTape() 和 ejectTape() 方法和 playTape()很相似

错误处理如下:

@IoHandlerTransition(on = MESSAGE_RECEIVED, in = ROOT, weight = 10)
public void error(Event event, StateContext context, IoSession session, Command cmd) {
    session.write("- Cannot " + cmd.getName() + " while " 
           + context.getCurrentState().getId().toLowerCase());
}
主方法:
private static IoHandler createIoHandler() {
    StateMachine sm = StateMachineFactory.getInstance(IoHandlerTransition.class).create(EMPTY, new TapeDeckServer());
        
    return new StateMachineProxyBuilder().setStateContextLookup(
            new IoSessionStateContextLookup(new StateContextFactory() {
                public StateContext create() {
                    return new TapeDeckContext();
                }
            })).create(IoHandler.class, sm);
}

// This code will work with MINA 1.0/1.1:
public static void main(String[] args) throws Exception {
    SocketAcceptor acceptor = new SocketAcceptor();
    SocketAcceptorConfig config = new SocketAcceptorConfig();
    config.setReuseAddress(true);
    ProtocolCodecFilter pcf = new ProtocolCodecFilter(
            new TextLineEncoder(), new CommandDecoder());
    config.getFilterChain().addLast("codec", pcf);
    acceptor.bind(new InetSocketAddress(12345), createIoHandler(), config);
}

// This code will work with MINA trunk:
public static void main(String[] args) throws Exception {
    SocketAcceptor acceptor = new NioSocketAcceptor();
    acceptor.setReuseAddress(true);
    ProtocolCodecFilter pcf = new ProtocolCodecFilter(
            new TextLineEncoder(), new CommandDecoder());
    acceptor.getFilterChain().addLast("codec", pcf);
    acceptor.setHandler(createIoHandler());
    acceptor.setLocalAddress(new InetSocketAddress(PORT));
    acceptor.bind();
}

reateIoHandler() 方法创建了一个状态机,这个和我们之前所做的相似。除了我们一个IoHandlerTransition.class类来代替Transition.class 在StateMachineFactory.getInstance(...)方法中。这是我们在使用 @IoHandlerTransition 声明的时候必须要做的。当然这时我们使用了一个IoSessionStateContextLookup和一个自定义的StateContextFactory类,这个在我们创建一个IoHandler 代理时被使用到了。如果我们没有使用IoSessionStateContextLookup ,那么所有的客户端将会使用同一个状态机,这是我们不希望看到的。

main()方法创建了SocketAcceptor实例,并且绑定了一个ProtocolCodecFilter ,它用于编解码命令对象。最后它绑定了12345端口和IoHandler的实例。这个oHandler实例是由createIoHandler()方法创建的。




apache mina 学习(十一)-----状态机(stateMachine)

当我们在开发复杂的网络应用的时候往往需要一个状态的设计,下面就以官网的一个收录机播放为例来说明: 收录机状态之间的转换我们应该不难理解:首先是空状态,就是什么磁带就没放进去然后是有磁带的状态,这两个...
  • Cages
  • Cages
  • 2012年03月21日 09:28
  • 3134

apache mina 学习(十二)-----状态机(stateMachine)

mina状态机的工作原理: mina中引入了StateContext对象,顾名思义是一个状态上下文对象,用来保存当前的状态,当代理state对象的方法被调用的时候,这个上下文对象会通知state...
  • Cages
  • Cages
  • 2012年03月21日 15:06
  • 5636

《Apache MINA 2.0 用户指南》第十四章:状态机

本章对 MINA 框架中最复杂的一个主题 - 状态机进行了深入分析和讨论。内容包括状态机小例子、状态机的工作原理、注解匹配、状态继承、错误处理等等主题和内容,全文穿插大量示例代码,避免我们深陷于复杂的...
  • defonds
  • defonds
  • 2014年01月14日 17:37
  • 3756

Apache mina2 用户指南(十四)状态机

如果你在使用 MINA 开发一个具有复杂网络的交互的应用,在某种情况下你可能会发现你自己试着使用经典的 状态模式 以尝试解决其复杂性。但是,在你那么干之前,你可能想要检出 mina-statema...

OpenGL入门学习之十三——OpenGL是一个状态机

前一段时间里,论坛有位朋友问什么是状态机。按我的理解,状态机就是一种存在于理论中的机器,它具有以下的特点: 1. 它有记忆的能力,能够记住自己当前的状态。 2. 它可以接收输入,根据输入的内容和自...

Mina状态机StateMachine

首先,关于状态机的一个极度确切的描述是它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节...
  • canlets
  • canlets
  • 2013年11月06日 18:53
  • 1209

Mina状态机StateMachine()

接下来我们要把这样的方式用在通信中。用通信的方式来模拟录放机的按钮。 我们先看状态的定义:...
  • canlets
  • canlets
  • 2013年11月06日 19:59
  • 1907

Mina State machine状态机讲解

原文地址:Mina State machine(Apache Mina User guide Chapter14 State machine) 如果您使用的是Mina与复杂网络开发应用程序交互,你可能...
  • boonya
  • boonya
  • 2016年06月16日 15:30
  • 2517

Mina状态机介绍(Introduction to mina-statemachine)

如果你使用Mina开发一个复杂的网络应用时,你可能在某些地方会遇到那个古老而又好用的状态模式,来使用这个模式解决你的复杂应用。然而,在你做这个决定之前,你或许想检出Mina的状态机的代码,它会根据当前...
  • whycold
  • whycold
  • 2011年01月19日 23:51
  • 2682

状态机的使用

  • 2013年09月22日 14:42
  • 178KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:apache mina 学习(十三)-----状态机和IoHander配合使用
举报原因:
原因补充:

(最多只允许输入30个字)