連載の最後となる今回は,WebSocketのトピックをいくつか取り上げたあと,WebSocketChatのアプリケーション化と配布物の生成を行ないます。
WebSocketのセキュリティ
WebSocketは,リビジョン76で接続処理に手を加え,堅牢性が増しています。また,HTTPと同様なOriginを基にしたセキュリティモデルを採用しています。Ajaxと違い,現行のWebSocket対応ブラウザ側には,same originポリシーによる制限はないようです。
Jetty7はそのままでは,cross originが可能です。制限が必要な場合は,「CrossOriginFilter」(※1)を使用します。
- ※1
- Servletなら「web.xml」ファイルの「filter-mapping」に,今回のようなアプリケーションであれば「ServletContextHandler」インスタンスに設定するのが良いでしょう。
最新の仕様
第3回「データ送信の詳細」の項で,フレームタイプについて説明しました。最新の仕様では,フレームタイプの扱いが大きく変更になりそうです。ドラフト版のリビジョン76の段階では,フレームタイプがテキストフレームとバイナリフレームに大別されていましたが,執筆段階の最新のドラフト版ではフレームの仕様が大きく変わり,テキストやバイナリに関わらず,「TLV(type-length-value)」形式になったようです。しかし,ドラフト版のリビジョン番号もまだ割り当てられていないため,今後どのように変更されるのかはわかりません。
この変更された仕様をJettyが実装した場合,Jettyのフレームタイプの定数(※2)の扱いも変更されると思いますが,今回サンプルとして作成しているチャットアプリケーションは,受信したデータのフレームタイプを変更せずに送信しているため,メソッドが変更される等の大きな変更がない限り影響はないでしょう。
第3回「WebSocketプロトコル」の項でも言及しましたが,サーバやクライアントがどのリビジョンに対応しているのかを考慮し,ライブラリのバージョンを変更してください。
- ※2
- テキストフレーム用の「WebSocket.SENTINEL_FRAME(=0x00)」とバイナリフレーム用の「WebSocket.LENGTH_FRAME(=0x80)」のこと。
アイコンの準備
アプリケーション化を行なう前に,3種類のアイコンを準備しましょう(※3)。1つは,WindowsのタスクトレイやMacのステータスメニューに表示するためのアイコンです。2つ目はWindows用のアプリケーションアイコン,3つ目はMac OS X用のアプリケーションアイコンです(※4)。
「src/main/resources」内に,「images」という名前の新しいディレクトリを作成し,これらのアイコンを入れてください。
- ※3
- この連載で使用しているアイコンがダウンロードできます。
- ※4
- Linuxのアプリケーション化は,筆者の環境で正常に動作するMavenのプラグインが見つからなかったため,今回は言及しません。
メニューの作成
ここまでに作成してきたWebSocketChatは,GUIが定義されていません。このままでは,起動していることもわかりませんし(※5),終了することもできません。最低限のGUIとして,終了メニューを作成します。
そこで,第4回で作成したWebSocketChatクラスを以下のように変更しましょう。
リスト1 WebSocketChatクラス
package webSocketChat;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
public class WebSocketChat {
public static void main(String[] args) throws Exception {
new WebSocketChat();
}
public WebSocketChat() throws Exception {
MenuItem quitMenuItem = new MenuItem("Quit");
quitMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
PopupMenu popupMenu = new PopupMenu();
popupMenu.add(quitMenuItem);
URL imageUrl = this.getClass().getClassLoader().getResource("images/icon.png");
TrayIcon trayIcon = new TrayIcon(Toolkit.getDefaultToolkit().createImage(imageUrl));
trayIcon.setImageAutoSize(true);
trayIcon.setToolTip("WebSocketChat");
trayIcon.setPopupMenu(popupMenu);
SystemTray systemTray = java.awt.SystemTray.getSystemTray();
systemTray.add(trayIcon);
Server server = new Server(8040);
ResourceHandler rh = new ResourceHandler();
rh.setResourceBase(this.getClass().getClassLoader().getResource("html").toExternalForm());
MyWebSocketServlet wss = new MyWebSocketServlet();
ServletHolder sh = new ServletHolder(wss);
ServletContextHandler sch = new ServletContextHandler();
sch.addServlet(sh, "/ws/*");
HandlerList hl = new HandlerList();
hl.setHandlers(new Handler[] {rh, sch});
server.setHandler(hl);
server.start();
}
}
修正内容を順に解説します。
MenuItem quitMenuItem = new MenuItem("Quit");
quitMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
「Quit」というラベルをつけてメニュー項目を作成しています。そして,無名クラス内でアプリケーション終了の処理を定義し,メニュー項目が選択された時の動作に追加します。
PopupMenu popupMenu = new PopupMenu();
popupMenu.add(quitMenuItem);
メニューのアイコンをクリックした時に表示するポップアップメニューを作成し,メニュー項目を追加します。
URL imageUrl = this.getClass().getClassLoader().getResource("images/icon.png");
TrayIcon trayIcon = new TrayIcon(Toolkit.getDefaultToolkit().createImage(imageUrl));
trayIcon.setImageAutoSize(true);
trayIcon.setToolTip("WebSocketChat");
trayIcon.setPopupMenu(popupMenu);
メニューアイコンの画像を,トレイアイコンに指定します。環境によってメニューの高さが違う可能性を考慮し,大きめの画像を準備して,「setImageAutoSize」で表示サイズを自動的に変更されるようにしました。そして,利用者がWebSocketChatとわかるようにツールチップも指定し,ポップアップメニューを登録しています。
SystemTray systemTray = java.awt.SystemTray.getSystemTray();
systemTray.add(trayIcon);
システムトレイは,Windowsではタスクトレイ,Macではステータスメニュー,Linuxではノーティフィケーションエリアやシステムトレイ等を指します(※6)。このシステムトレイにトレイアイコンを追加します。
それでは,EclipseからWebSocketChatを起動してみてください。
それぞれのOSで,メニューが表示するされることを確認できました。
- ※5
- 正確には,Mac OS XではDock内でアプリケーションアイコンが跳ね続けます。
- ※6
- Linuxでは,デスクトップ環境によって名前が違います。

