Cometを利用したサーブレットの例
それでは、早速Cometを利用したアプリケーションを作ってみよう。TomcatでComtを使用するには、HttpServletにおいてorg.apache.catalina.CometProcessorというインタフェースをimplementsする。このインタフェースにはeventというメソッドが宣言されている。CometProcessorをimplementsしたサーブレットにアクセスがあると、org.apache.catalina.CometEventというイベントが発生し、doGetやdoPostの代わりにeventメソッドにCometEventが渡されて呼び出される。
したがって基本的な形はリスト23のようになる。eventメソッド内にリクエストを処理するコードを記述しておけばよい。
リスト23 Cometを使うサーブレットプログラムの基本形
public class CometSampleServlet
extends HttpServlet implements CometProcessor {
public void event(CometEvent event)
throws IOException, ServletException {
//ここに処理を記述する
}
}
CometEventには次に示す4種類のタイプが定義されている。セッションを終了するにはCometEventのcloseメソッドを呼び出す。
- EventType.BEGIN: コネクションが確率した際のイベント
- EventType.END: リクエストの処理が終了した際のイベント
- EventType.ERROR: I/Oエラーなど、何らかのエラーが発生した際のイベント
- EventType.READ: データの入力があった場合のイベント
リスト24に、Cometを使用したサーブレットの例を示す。このサーブレットはリクエストを発行したブラウザに対して、コネクションを張ったまま5秒毎に時刻を送り続けるという処理をする。データの送信はMessageSenderというスレッドで行う。
リスト24 Cometを使うサーブレットの例(CometSampleServlet.java)
package sample;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;
public class CometSampleServlet
extends HttpServlet implements CometProcessor {
protected ArrayList<HttpServletResponse> connections =
new ArrayList<HttpServletResponse>();
protected MessageSender sender = null;
/**
* アクセスがあった際に呼び出されるイベントハンドラ
*/
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
// データの送信を開始
request.setAttribute("org.apache.tomcat.comet", Boolean.TRUE);
PrintWriter writer = response.getWriter();
writer.println("<!doctype html public \"-//w3c//dtd html 4.0 transitional//en\">");
writer.println("<head><title>Comet Sample</title></head><body>");
writer.flush();
synchronized(connections) {
connections.add(response);
}
}
else if (event.getEventType() == CometEvent.EventType.ERROR) {
// エラー発生時
synchronized(connections) {
connections.remove(response);
}
event.close();
}
else if (event.getEventType() == CometEvent.EventType.END) {
// データの送信を終了
synchronized(connections) {
connections.remove(response);
}
PrintWriter writer = response.getWriter();
writer.println("</body></html>");
event.close();
}
else if (event.getEventType() == CometEvent.EventType.READ) {
}
}
/**
* 初期化処理
*/
public void init() throws ServletException {
sender = new MessageSender();
Thread senderThread = new Thread(sender);
senderThread.setDaemon(true);
senderThread.start();
}
/**
* 終了処理
*/
public void destroy() {
connections.clear();
sender.stop();
sender = null;
}
/**
* データ送信用のスレッド
*/
public class MessageSender implements Runnable {
// 後述
}
}
まず、初期化段階でMessageSenderスレッドを起動して送信の準備を行う(initメソッド)。eventメソッドでは、BEGINイベントを受け取った場合にHTMLのヘッダを送信する。複数のコネクションを処理するために、受け取ったHttpResponseはリストに保持しておく。ENDイベントの場合はHTMLの閉じタグを送信してセッションを終了する。ERRORイベントでも同様にセッションを終了する。READイベントは今回は処理しない。