移動したら、サーブレットの作成に移ります。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インターフェイスが使われています。
それでは、作成したサーブレットをコンパイルしましょう。
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)
図5 チャット中のクライアント(2)
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技術からマーケティング、金融テクノロジーなどさまざまな分野で活動中。
主な著書
『最速導入!オープンソースでつくる実用オンラインショップ』