連載
» 2007年12月12日 00時00分 公開

Tomcat 6で実現!Ajaxを超える通信技術CometTomcatはどこまで“安全”にできるのか?(3)(3/3 ページ)

[x-labチーム,株式会社アメニクス]
前のページへ 1|2|3       

サーブレットにCometを実装する

 移動したら、サーブレットの作成に移ります。Cometはイベント受信後、エディタでCometServlet.javaを作成します。サーブレットには、以下の内容を記述していきます。

CometServlet.java(※Tomcatのリファレンスページにある内容を基に作成)
import java.util.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;


public class CometServlet
extends HttpServlet implements CometProcessor {

    protected ArrayList<HttpServletResponse> connections
        = new ArrayList<HttpServletResponse>();
    protected MessageSender messageSender = null;

    public void init() throws ServletException {
        messageSender = new MessageSender();
        Thread messageSenderThread =
            new Thread(messageSender, "MessageSender["
            + getServletContext().getContextPath() + "]");
        messageSenderThread.setDaemon(true);
        messageSenderThread.start();
    }
    public void destroy() {
        connections.clear();
        messageSender.stop();
        messageSender = null;
    }

    /**
    * Process the given Comet event.
    *
    * @param event The Comet event that will be processed
    * @throws IOException
    * @throws ServletException
    */
    public void event(CometEvent event)
    throws IOException, ServletException {

        HttpServletRequest request = event.getHttpServletRequest();
        HttpServletResponse response = event.getHttpServletResponse();

        if ("POST".equals(request.getMethod())) {
            final String user = request.getParameter("user");
            final String message = request.getParameter("message");
            messageSender.send(user,message);

            event.close();
            return;
        }

        if (event.getEventType() == CometEvent.EventType.BEGIN) {
            event.setTimeout(60 * 1000 * 30);
            log("Begin for session: "
                + request.getSession(true).getId());

            response.setContentType("text/html;charset=UTF-8");
            PrintWriter writer = response.getWriter();
            writer.println("<!doctype html public \"-//w3c//dtd html"
                +" 4.0 transitional//en\">");
            writer.println("<head><title>チャットメッセージ</title>"
                +"</head><body bgcolor=\"#FFFFFF\">");
            writer.flush();
            synchronized(connections) {
                connections.add(response);
            }
        } else if(event.getEventType() == CometEvent.EventType.ERROR){
            log("Error for session: "
                + request.getSession(true).getId());
            synchronized(connections) {
                connections.remove(response);
            }
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.END) {
            log("End for session: "
                + request.getSession(true).getId());
            synchronized(connections) {
                connections.remove(response);
            }
            PrintWriter writer = response.getWriter();
            writer.println("</body></html>");
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.READ){
        }
    }

    public class MessageSender implements Runnable {
        protected boolean running = true;
        protected ArrayList<String> messages=new ArrayList<String>();
        public MessageSender() { }
        public void stop() {
            running = false;
        }
        /**
        * Add message for sending.
        */
        public void send(String user, String message) {
            synchronized (messages) {
                messages.add("[" + user + "]: " + message);
                messages.notify();
            }
        }
        public void run() {
            while (running) {
               if (messages.size() == 0) {
                    try {
                        synchronized (messages) {
                            messages.wait();
                        }
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
                synchronized (connections) {
                    String[] pendingMessages = null;
                    synchronized (messages) {
                        pendingMessages
                            = messages.toArray(new String[0]);
                        messages.clear();
                    }
                    // Send any pending message
                    // on all the open connections
                    for (int i = 0; i < connections.size(); i++) {
                        try {
                            PrintWriter writer
                                = connections.get(i).getWriter();
                            for(int j=0;j<pendingMessages.length;j++){
                                writer.println(pendingMessages[j]
                                    + "<br>");
                            }
                            writer.flush();
                        } catch (IOException e) {
                            log("IOExeption sending message", e);
                        }
                    }
                }
            }
        }
    }
}

 以上でサーブレットの記述は完了しました。

 Cometの実現には、Tomcat 6から提供されたorg.apache.catalina.CometEventクラスorg.apache.catalina.CometProcessorインターフェイスが使われています。

Cometでチャットをしてみよう!

 それでは、作成したサーブレットをコンパイルしましょう。

javac -classpath /opt/tomcat6/lib/servlet-api.jar:/opt/tomcat6/lib/catalina.jar CometServlet.java

 無事にエラーなく終了すれば、作成完了です。最後に、Tomcatの再起動を実行します。

/etc/rc.d/init.d/tomcat restart

 再起動が完了したら、実際に作成したチャットを開いてみましょう。「http://[サーバのIPアドレス]:8080/jsp/CometChat.jsp」を開いて、発言してみましょう。

 発言をすると、同時に接続しているページ全部へメッセージが送信され、描画されるのが分かります。複数のウィンドウで同時に接続して行うと、以下のようになります。

図4 チャット中のクライアント(1) 図4 チャット中のクライアント(1)
図5 チャット中のクライアント(2) 図5 チャット中のクライアント(2)

次回はTomcatが持つセキュリティリスクについて

 TomcatもCometをサポートし、閲覧者同士がリアルタイムに情報交換できるWebアプリケーションの提供など可能になったことは大きな進展ですね。

 Cometの活用事例については、@ITの記事「リバースAjax機能はAjax+Javaをもっとやさしくする?の「サーバプッシュ型Ajaxアプリケーションの応用例」や@ITの記事「サーバが通信を開始できるComet活用Webチャット」の「ハイライト2・快適かつ強力なチャットサービスLingr」に詳しいので、ご参照ください。

 今回まではTomcatの設定や運用、新機能について触れてきましたが、次回からはいよいよTomcatが持つセキュリティのリスクについて触れていきます。

著者プロフィール

x-lab チーム

株式会社アメニクスのR&D部門として、企業の価値向上を目的に結成された研究開発チーム(x-lab=amenix laboratory)。

アメニクスの社員をはじめ、システム開発技術者のみに限らず、MBA教授や外資系出身エンジニアなど幅広いメンバーが所属している。IT技術からマーケティング、金融テクノロジーなどさまざまな分野で活動中。


主な著書

『最速導入!オープンソースでつくる実用オンラインショップ』



前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。