Hatena::ブログ(Diary)

ショータローDiary

2010-02-06

Fedone サーバに ClientBackend を使ってメッセージを送ってみるテスト

| 16:51 |

ローカルに建てた Google Waveプロトコル実験実装 Fedone Server に対して、ClientBackend クラスを使ってメッセージを送ってみるテスト


FedOneサーバインストールはココ↓を参照

http://rainbowdevil.jp/wave/install-fedone.html


public class HelloWave {
	public static void main(String[] args) throws Exception {
		ClientBackend backend = new ClientBackend("test1@domainname", "localhost", 9876);
		try {
			//Create Wave
			BlockingSuccessFailCallback<ProtocolSubmitResponse, String> callback = BlockingSuccessFailCallback.create();
			backend.createConversationWave(callback);
			callback.await(1, TimeUnit.MINUTES);

			//Get Wave
			ClientWaveView indexWave = backend.getIndexWave();
			List<IndexEntry> index = ClientUtils.getIndexEntries(indexWave);
			ClientWaveView wave = backend.getWave(index.get(0).getWaveId());

			//Send Wavelet Delta
			WaveletData waveletData = ClientUtils.getConversationRoot(wave);
			BufferedDocOp docOp = waveletData.getDocuments().get(DocumentConstants.MANIFEST_DOCUMENT_ID);
			String documentId = backend.getIdGenerator().newDocumentId();
			WaveletDelta waveletDelta = ClientUtils.createAppendBlipDelta(docOp, backend.getUserId(), documentId, "Hello Wave!");
			backend.sendAndAwaitWaveletDelta(waveletData.getWaveletName(), waveletDelta, 1, TimeUnit.MINUTES);
		} finally {
			backend.shutdown();
			System.exit(0);
		}
	}
}

2010-01-07

JSONで通信する汎用的なjQueryのWebSocketプラグインを作ってみた

| 23:51 |

単純に文字列しか送れない Web Sockets APIプロトコル的にはバイナリも送れるけど)なので、ちょっと色々送ろうと思うと、やっぱり JSON で送りたくなる。

どうせ絶対毎回使うと思うので、汎用的なプラグインにしてみた。


jQuery Web Sockets Plugin

http://code.google.com/p/jquery-websocket/


やれることは、

これのみ。あとは使う人の自由。


通常と違うところは、


このプラグインJetty で WebSocket を使ってみる - ショータローDiaryで使ったコードを書き換えるとこんな感じ↓

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<section id="content"></section>
<input id="message" type="text"/>
<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1.3")</script>
<script src="http://jquery-json.googlecode.com/files/jquery.json-2.2.min.js"></script>
<script src="http://jquery-websocket.googlecode.com/files/jquery.websocket-0.0.1.js"></script>
<script>
var ws = $.websocket("ws://127.0.0.1:8080/", {
	events: {
		message: function(e) { $('#content').append(e.data + '<br>') }
	}
});
$('#message').change(function(){
  ws.send('message', this.value);
  this.value = '';
});
</script>
</body>
</html>

この単純すぎるコードではあまり恩恵はない(window.unload での close はプラグインでやってるのでその分は楽だけど)ので、イベント多用するサンプルを作ってみたけど、何か面白くないのでやり直し。。


でも、これが出来るだけで、かなり使いやすくなったはず! ということで、誰か面白いの作ったら教えて下さいw

2009-12-20

MMTBでLTした

| 11:00 |

前の会社にいた時は社内向けにLTっぽい事してたけど、公の場では人生初LT。

とは言っても、知り合いが大半の場でしたがw


みんなで持ち寄るIT技術定例勉強会(MMTB)

http://d.hatena.ne.jp/mmtb/


そのときのスライド

http://docs.google.com/present/view?id=dddvzhrc_3frv8djhr


デモは先週書いたJetty で WebSocket を使ってみる - ショータローDiaryそのままという手抜きですがw



でもまぁ、何となく今年のTryだった「LTする」ってのは、ギリギリ達成されました。パチパチ

来年はもっと発表して行こうと思う(ネタがあれば)

mmtbmmtb 2009/12/20 12:07 ひらのです。
昨日はありがとうございました。
MMTBの今年の最後は飛び込みでの「LT」でバシッと〆ていただけましたね。
参加された方々にとっても刺激的で勉強になったのではないかと思います。
私自身また聞きたいので、来年も是非何回でもよろしくお願いします!

2009-12-14

Jetty で WebSocket を使ってみる

| 02:27 |

Jetty 7.0.1.v20091125 で、HTML5 の WebSocket がサポートされているので、Chrome から繋げてみる。


WebSocketServlet によるサンプルが紹介されているので、

Jetty/Feature - Eclipsepedia

WebSocketHandler で。


こんな感じ。

public class MemberSocket implements WebSocket {
	static Set<MemberSocket> members = new CopyOnWriteArraySet<MemberSocket>();
	Outbound outbound;

	@Override
	public void onConnect(Outbound outbound) {
		System.out.println("onConnect:" + this);
		this.outbound = outbound;
		members.add(this);
	}

	@Override
	public void onDisconnect() {
		System.out.println("onDisconnect:" + this);
		members.remove(this);
	}

	@Override
	public void onMessage(byte frame, String data) {
		System.out.println("onMessage:" + this);
		for (MemberSocket member : members) {
			try {
				member.outbound.sendMessage(frame, data);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void onMessage(byte frame, byte[] data, int offset, int length) {
		System.out.println("onMessageOffset:" + this);
	}

	public static void main(String[] args) throws Exception {
		Server server = new Server(8080);
		server.setHandler(new WebSocketHandler() {
			@Override
			protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
				MemberSocket memberSocket = new MemberSocket();
				System.out.println("doWebSocketConnect:" + memberSocket);
				return memberSocket;
			}
		});
		server.start();
	}
}

見たままですね。

offset ありの onMessage はどういう場合に呼ばれるんだろ??



クライアントは、本家のWebSocket Chatでもいいのだけど、何か無駄にごちゃごちゃしてるので、おおたにさんのところにあったEmerge Technology: WebSocketでChatを作ってみたjQuery 化したもの。

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<section id="content"></section>
<input id="message" type="text"/>
<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1.3")</script>
<script>
var ws = new WebSocket("ws://127.0.0.1:8080/");
ws.onmessage = function(m) {
  $('#content').append(m.data + '<br>');
};
$('#message').change(function(){
  ws.send(this.value);
  this.value = '';
});
$(window).unload(function(){
  ws.close();
});
</script>
</body>
</html>

コネクションが解放されない問題Emerge Technology: ChromeとWebSocketも対応済み。Chromeバグなんだろか。



で、実行すると、、

f:id:shootaroo:20091215013935p:image

うん、チャットできてますね。



一応、Maven であれば jetty-websocket に依存させるだけでよい。らくちん。

<dependency>
	<groupId>org.eclipse.jetty</groupId>
	<artifactId>jetty-websocket</artifactId>
	<version>7.0.1.v20091125</version>
</dependency>


もう Comet 要らないな。

2009-12-10

T2 を Jetty Embedded で直接動かす

| 08:21 |

軽量な Web フレームワークとして T2 が気になるところなのですが、最近のマイブームクライアントサイド Java アプリなので、それに組み込んでみたらどうかと考えてみたり。

よりシンプルに動かしたいので、軽量なアプリケーションサーバの代表格である Jetty で動かそうかと。それも直接に。


T2 は ServletFilter ベースなので、普通に動かすには war ファイルを作って(それか webapp ディレクトリを指定して)デプロイをしなければならないわけですが、組み込みアプリデプロイなんて行為は必要ない。デプロイするには jetty-deploy に依存する必要もあり、イケてない。

最新の Jetty 7 は、機能がかなり小分けに jar 化されていて、最小構成の jetty-server からの依存だと、JSP はおろか Servlet すら動かない構成にすることができる。直接動かすって何かというと、この最小構成の Jetty(仮に Jetty Embedded と呼ぶ)で、デプロイも無しに動かすということ。

Jetty/Reference/Dependencies - Eclipsepedia


Servlet も動かない Jetty Embedded で処理を実行する唯一の方法は、リクエストを処理する Handler インタフェースを実装したクラスを作って、Server に登録すること。

Jetty/Tutorial/Embedding Jetty - Eclipsepedia

そこで、T2 の根幹である T2Filter をラッピングした Handler を作れば良いと思って、作ったのが↓

public class T2Handler extends AbstractHandler {
	protected Filter t2Filter;
	protected Context context;
	protected Dictionary<String, String> initParam;

	public T2Handler() {
		t2Filter = new T2Filter();
		initParam = new Hashtable<String, String>();
	}

	@Override
	public void handle(String target, Request baseRequest,
			HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException {

		// FilterChain を偽造
		FilterChain chain = new FilterChain() {
			public void doFilter(ServletRequest request, ServletResponse response)
					throws IOException, ServletException {
			}
		};
		t2Filter.doFilter(request, response, chain);
		baseRequest.setHandled(true);
	}

	@Override
	protected void doStart() throws Exception {
		context = ContextHandler.getCurrentContext();
		// FilterConfig を偽造
		FilterConfig config = new FilterConfig() {
			public ServletContext getServletContext() {
				return context;
			}

			public Enumeration<String> getInitParameterNames() {
				return initParam.keys();
			}

			public String getInitParameter(String name) {
				return initParam.get(name);
			}

			public String getFilterName() {
				return "t2";
			}
		};
		t2Filter.init(config);
		super.doStart();
	}

	@Override
	protected void doStop() throws Exception {
		t2Filter.destroy();
	}

	public void setRootPackage(String value) {
		initParam.put("t2.rootpackage", value);
	}
}

Handler は、ほとんど Filter と同じ仕組みになっているので、

  • Handler.handle() から Filter.doFilter()
  • Handler.doStart() から Filter.init()
  • Handler.doStop() から Filter.destroy()

を呼んであげて、initParam で指定する t2.rootpackage を設定する setter だけとりあえず用意すれば良い。至って簡単。ただし、Filter 固有の FilterConfig と FilterChain が無いので、偽造して渡してあげる必要がある。ここだけシンプルさに欠ける。。


で、この T2Handler をサーバーに登録して起動する main クラスを作っておしまい。

public class Main {
	public static void main(String[] args) throws Exception {
		T2Handler t2Handler = new T2Handler();
		t2Handler.setRootPackage("sample.page");

		SessionHandler sessionHandler = new SessionHandler();
		sessionHandler.setHandler(t2Handler);

		ContextHandler contextHandler = new ContextHandler();
		contextHandler.setHandler(sessionHandler);
		
		Server server = new Server(8080);
		server.setHandler(contextHandler);
		server.start();
	}
}

あとは適当な Page クラスを用意して実行すれば、、

f:id:shootaroo:20091210025917p:image

おおお!ちゃんと動いてますね!



以下、依存した jar 達。

  439,063 t2-0.6.2-ga.jar
  348,057 commons-0.6.5-ga.jar

  250,557 jetty-server-7.0.1.v20091125.jar
  179,079 jetty-util-7.0.1.v20091125.jar
  106,778 jetty-http-7.0.1.v20091125.jar
  105,112 servlet-api-2.5.jar
   67,325 jetty-io-7.0.1.v20091125.jar
   19,332 jetty-continuation-7.0.1.v20091125.jar

   23,445 slf4j-api-1.5.8.jar
    5,284 slf4j-nop-1.5.8.jar

こう比較すると T2 って思ったよりデカイ。(十分小さいけど。)

Jetty みたいにもうちょっと小分けにすれば小さくなるんじゃなかろうか。org.t2framework.t2.format.amf* 配下とか、AMF 使わなければ要らないんじゃ?と思って、削ってみたら(依存する箇所がいくつかあったので、若干修正込み)、

  348,057 commons-0.6.5-ga.jar
  291,324 t2-without-amf-0.6.3-SNAPSHOT.jar
  250,557 jetty-server-7.0.1.v20091125.jar

commons よりも小さくなった。

ミニマルREST フレームワーク作ろうとしてたけど、これなら T2 使えばいいかもしれない。。むぅ。

yone098yone098 2009/12/10 08:36 ファイルサイズは確かに仰る通りです。
amf部は、必須では無いので使わない人にとっては切り離せた方が嬉しいですかね?

shootarooshootaroo 2009/12/10 14:31 限定的な需要かもしれませんけど嬉しいです。T2 のゴールに「極めて小さく」と在るので、ファイルサイズが小さいこともファクターとして有りかと。
と言いつつ、ファイルサイズはそこまで重要ではなくて、amf 部に依存してるのを切り離してもらいたいですね。まだきちんと確認してないですけど PermGen を圧迫してると思うので。