2007 年 1 月 23 日 23 時 7 分

MessageDispatcher クラス


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


次に、メッセージを読み出し、
RFBDisplay 実装クラスに転送するクラスを作る。

このクラスは各種ハンドシェイクの後に実行される
主処理として、RFBHandler を実装することにする。

========== MessageDispatcher.java ==========

package jp.loafer.rfb.server;

import java.io.IOException;

import jp.loafer.rfb.RFBContext;
import jp.loafer.rfb.RFBHandler;
import jp.loafer.rfb.io.RFBInputStream;
import jp.loafer.rfb.io.RFBOutputStream;
import jp.loafer.rfb.message.ClientInitMessage;
import jp.loafer.rfb.message.PixelFormat;
import jp.loafer.rfb.message.ServerInitMessage;
import jp.loafer.rfb.message.client.*;

/**
* クライアントメッセージを読み取って転送するクラス。
* @author kes
*/
public class MessageDispatcher implements RFBHandler {

    /**
     * {@link MessageDispatcher} のインスタンスを作成。
     * @param display 仮想画面。
     */
    public MessageDispatcher(RFBDisplay display) {
        if (display == null) throw new NullPointerException();
        this.display = display;
    }

    /**
     * @see RFBHandler#execute(RFBContext, RFBInputStream, RFBOutputStream)
     */
    public void execute(RFBContext context, RFBInputStream in,
            RFBOutputStream out) throws IOException {

        // 初期化メッセージを交換
        {
            // ClientInit

            /* ClientInitMessage client = */
            in.readMessage(context, ClientInitMessage.class);   

            // TODO: 共有接続のフラグによって挙動を変える

            // ServerInit

            int width = display.getWidth();
            int height = display.getHeight();
            PixelFormat format = display.getDefaultPixelFormat();
            String name = display.getName();

            ServerInitMessage message
                    = new ServerInitMessage(width, height, format, name);
            out.writeMessage(context, message);
            out.flush();
           
        }
       
        // 画面を初期化
        display.initialize(context, out);

        // メッセージループへ
        for (;;) {

            // メッセージを受け取り
            ClientMessage message = getMessage(context, in);
           
            // 送り出す
            dispatchMessage(message);

        }

    }

    // ストリームよりクライアントメッセージを読み出す
    protected ClientMessage getMessage(
            RFBContext context, RFBInputStream in) throws IOException {

        // 1 バイト先読み
        in.mark(1);
        int type = in.readU8();
        in.reset();

        Class<? extends ClientMessage> messageClass;

        switch (type) {
        case ClientMessage.SET_PIXEL_FORMAT:
            messageClass = SetPixelFormatMessage.class;
            break;
        case ClientMessage.FIX_COLOR_MAP_ENTRIES:
            messageClass = FixColorMapEntriesMessage.class;
            break;
        case ClientMessage.SET_ENCODINGS:
            messageClass = SetEncodingsMessage.class;
            break;
        case ClientMessage.FRAMEBUFFER_UPDATE_REQUEST:
            messageClass = FramebufferUpdateRequestMessage.class;
            break;
        case ClientMessage.KEY_EVENT:
            messageClass = KeyEventMessage.class;
            break;
        case ClientMessage.POINTER_EVENT:
            messageClass = PointerEventMessage.class;
            break;
        case ClientMessage.CLIENT_CUT_TEXT:
            messageClass = ClientCutTextMessage.class;
            break;
        default:
            throw new IOException("unknown client message.");
        }
       
        return in.readMessage(context, messageClass);

    }

    // クライアントメッセージを処理し、振り分ける
    protected void dispatchMessage(ClientMessage message) throws IOException {
       
        switch (message.getType()) {
       
        case ClientMessage.SET_PIXEL_FORMAT:
            {
                SetPixelFormatMessage m = (SetPixelFormatMessage)message;
                display.handleSetPixelFormat(m);
            }
            break;
   
        case ClientMessage.FIX_COLOR_MAP_ENTRIES:
            {
                FixColorMapEntriesMessage m
                        = (FixColorMapEntriesMessage)message;
                display.handleFixColorMapEntries(m);
            }
            break;

        case ClientMessage.SET_ENCODINGS:
            {
                SetEncodingsMessage m = (SetEncodingsMessage)message;
                display.handleSetEncodings(m);
            }
            break;
           
        case ClientMessage.FRAMEBUFFER_UPDATE_REQUEST:
            {
                FramebufferUpdateRequestMessage m
                        = (FramebufferUpdateRequestMessage)message;
                display.handleFramebufferUpdateRequest(m);
            }
            break;
           
        case ClientMessage.KEY_EVENT:
            {
                KeyEventMessage m = (KeyEventMessage)message;
                display.handleKeyEvent(m);
            }
            break;

        case ClientMessage.POINTER_EVENT:
            {
                PointerEventMessage m = (PointerEventMessage)message;
                display.handlePointerEvent(m);
            }
            break;
   
        case ClientMessage.CLIENT_CUT_TEXT:
            {
                ClientCutTextMessage m = (ClientCutTextMessage)message;
                display.handleClientCutText(m);
            }
            break;

        default:
            // 未知のメッセージはそのまま渡す
            display.handleCustomMessage(message);
               
        }

    }

    private RFBDisplay display;

}

========== end of MessageDispatcher.java ==========

MessageDispatcher クラスの execute メソッドは、
無限ループとなっているため戻ってこない。
といっても、例外を発生させれば脱出は可能だ。

その代わり、読み取ったメッセージは、
コンストラクタで受け取った RFBDisplay に転送される。

このクラスを利用すると、処理の流れを手続き型から、
イベント駆動型に変更する事ができるというわけだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.