4月4日に「第1回(仮称)クラウド研究会@札幌」で、以下の3つのテーマでお話をさせていただきました。幹事の中村さん(@nakayoshix)には大変お世話になりました。どうもありがとうございました。
- Android + Mule ESB + Twitter + OpenX + Scala + EC2
- SimpleModeler + AppEngine
- g3フレームワーク
昨年の秋ぐらいに、SimpleModelerのAppEngine/JDO周り、静的モデル周りが一段落。まだまだ完成というわけではないんだけど、バランス的にそろそろ動的モデルを攻めてみようということで、ここ半年ほどはクラウド・アプリケーションにおける動的モデルの位置付けと実現方法について検討と試作を行ってきた。
11月にはPDC09に参加する機会があり、Windows Azureについて学ぶことができたのも大きな収穫だった。
システムの動的モデルでは、エンティティの状態遷移モデルがひとつの基本になるけど、システム全体の挙動をモデル化する手法は確立されていない。ユースケース・モデルとシステム実装を繋ぐ部分は依然として手作業になる。
もちろん、手作業といってもモデリング側も色々なモデルを用意しているし、システム側もJavaEEやSpringといったアプリケーション・フレームワークがかなりの仕事をしてくれるので、相当手間を省けるようにはなっている。
しかし、クラウド時代に入ってモデリング側の道具立ても、システム側のアプリケーション・フレームワークもゼロベースで再構築しなければならない状況になっているのは明らか。クラウド時代には非同期、並列、分散、故障、遅延を正面から取り扱わないといけない。アプリケーション・モデルではこれらの要因を捨象して、実装時に頑張るというわけにはいかないだろう。
そういった時代認識もあり、次世代のコンピューティング環境、その土台となるモデル体系とシステム基盤、アプリケーション・フレームワークについて、微力ながら色々と考えた結果到達した結論が「メッセージ・フロー」である。
メッセージ・フローを軸にしてユースケースからエンティティをつなぐ動的モデルの体系を構築し、できるだけインピーダンスミスマッチが発生しない形でDSLで記述しフレームワーク上で動作させる方法について、朧気ながら形がみえてきたような気がしており、その実現のためのDSL、DSLコンパイラ、フレームワークの開発が最近のボクのテーマになっている。
まだまだ、仕掛り中の状態なんだけど、今回はよい機会をいただいたので中間報告という形で発表させていただいた。
Android + Mule ESB + Twitter + OpenX + Scala + EC2
「Android + Mule ESB + Twitter + OpenX + Scala + EC2」ではボクが試行アプリケーションとして作成したMule ESBベースのアプリケーションを素材にメッセージ・フロー・アーキテクチャによるアプリケーションの考え方などを説明した。
ポイントとなるのは、以下のメッセージ・フロー図。コントロール・フローやデータ・フローを記述するための図はあるけど、メッセージ・フローを記述するための図が案外ないので、ボクのニーズに合わせて文法を定義した。詳細はいずれこのブログでも紹介しようと思っている。
Visioで作った図なんだけど、OpenOfficeにはない矢印を使っているためOpenOfficeでは描けないことが最近判明した。OpenOfficeでかける記法に修正する予定である。
SimpleModeler + AppEngine
「SimpleModeler + AppEngine」は、現在開発中のScalaベースのDSLモデルコンパイラSimpleModelerの紹介。
現在のところエンティティ・モデルからUMLクラス図とAppEngine/Javaのプログラムを生成できる。
動的モデルは、状態遷移図をUMLステートマシン図と状態遷移表に変換するところまで。
1月22日に開催されたAppEngine Ja Night #4で発表させてもらった時の資料「
クラウド・アプリケーション:DSL駆動アプローチ:SimpleModelerの試み」を使って説明を行った。AppEngine Ja Night #4では、時間的な問題で半分まで行かなかったのだけど、今回は最後まで通して説明することができた。
g3フレームワーク
「g3フレームワーク」は、現在開発中のメッセージ・フロー・ベースのアプリケーション・フレームワークである。専用のScala DSLで記述したアプリケーションを直接実行する。
メッセージ・フローの実行基盤としてはApache CamelのScala DSLに期待していたんだけど、内部構造がやや弱いような印象もあり、進捗もはかばかしくないようにみえる。また、Apach CamelそのものもAppEngineで動かすのは無理があるような感じでもあるので、Apache Camelの利用は断念して独自にDSLとフレームワークを開発することにした。
g3フレームワークとDSLは、以下の3つの用途をカバーすることを念頭に動作セマンティクスとDSLを設計している。
- Google AppEngine Java上で動作する
- Mule ESBなどのESB上で動作する
- シェルからコマンドとして実行できる
今の所、コマンドとして実行するという機能範囲を実装している。
ある程度形がついたところでAppEngine上に載せる予定。こちらは、TaskQueueを用いて直接実行させることを想定している。
並行してMule ESBへの対応も行いたいと考えている。こちらはDSLからXMLの定義ファイルを生成する形を想定している。Mule ESBを用いてEC2とWindows Azure上で動作させることができるようになることを期待している。
最終的には、DSLで記述したモデルから、用途に応じてAppEngine, EC2, Windows Azure向けのプログラムを生成し、適材適所でAppEngine, EC2, Windows Azureを選択できるようにするのが目標である。AppEngine, EC2, Windows Azureの混在環境でも有効に機能するはず。
説明/デモで用いたDSLは以下のもの。
リスト1[TwitterScan3.scala](ユーザ名、パスワードのところは改変)はTwitterのTLをAtomFeedで読んできてg3フレームワークのAtomFeedオブジェクトとして受け取るというもの。Scalaのcase sequence(PartialFunction)を使っているのがポイント。この構造にすることでリアクティブなアプリケーションを簡単に記述することができる。
TwitterScan3.scala
package org.goldenport.g3.app
import org.goldenport.g3._
import org.goldenport.g3.atom._
class TwitterScan3 extends G3Application {
service('demogon, "http://[user]:[passward]@twitter.com/statuses/user_timeline/demogon.atom")
start invoke("demogon") agent {
case AtomFeed(feed) => feed.toString
case _ => "???"
} agent {
x => println("==> " + x)
x
}
}
リスト2[Split4.scala]は、
Enterprise Integration PatternsのSplitterとAggregatorを記述したもの。現在の実装はSplitterがListの各要素ごとに分割したものを送信して、Aggregatorが集約してListに再構築する。Splitterは関数でカスタマイズできるようにする予定。
Split4.scala
package org.goldenport.g3.app
import org.goldenport.g3._
class Split4 extends G3Application {
agent('compute) {
case x: Int => x + 100
} aggregate()
start(List(1, 2, 3, 4, 5)) split() publish("compute")
}
参考:デモ結果
参考のために(長くなるので最後に付録的に)デモの実行結果を載せておきます。スナップショットが表示されているだけなので、中身を知らないと意味が分かりませんが参考ということで。
以下、TwitterScan3とSplit4のデモの様子。TwitterScan3は当日はデモが失敗したので初公開。TwitterScan3のデモは表示が長いのでSplit4、TwitterScan3の順番に並べている。
Split4デモ結果
> run org.goldenport.g3.app.Split4
[info]
[info] == compile ==
[info] Source analysis: 1 new/modified, 13 indirectly \
invalidated, 0 removed.
[info] Compiling main sources...
[warn] there were unchecked warnings; re-run with -unchecked for \
details
[warn] one warning found
[info] Compilation successful.
[info] Post-analysis: 257 classes.
[info] == compile ==
[info]
[info] == copy-resources ==
[info] == copy-resources ==
[info]
[info] == run ==
[info] Running org.goldenport.g3.Main \
org.goldenport.g3.app.Split4
G3Pipe.do_Process1(class \
org.goldenport.g3.G3StartNode):List(WrappedArray(org.goldenport.g3.app.Split4)) \
G3StartNode.do_Process: \
WrappedArray(org.goldenport.g3.app.Split4)
G3Publish.do_Process
G3Context.send
lookup = [compute], Some(org.goldenport.g3.G3AgentNode@1d01844a)
G3Pipe.do_Process1(class org.goldenport.g3.G3AgentNode):List(1)
G3Pipe.do_Process2(class org.goldenport.g3.G3AgentNode):1/List()
G3AgentNode.do_Process: 1
r = 101
terminal = List(1)
G3Publish.do_Process
G3Context.send
lookup = [compute], Some(org.goldenport.g3.G3AgentNode@1d01844a)
G3Pipe.do_Process1(class org.goldenport.g3.G3AgentNode):List(2)
G3Pipe.do_Process2(class org.goldenport.g3.G3AgentNode):2/List()
G3AgentNode.do_Process: 2
r = 102
terminal = List(2)
G3Publish.do_Process
G3Context.send
lookup = [compute], Some(org.goldenport.g3.G3AgentNode@1d01844a)
G3Pipe.do_Process1(class org.goldenport.g3.G3AgentNode):List(3)
G3Pipe.do_Process2(class org.goldenport.g3.G3AgentNode):3/List()
G3AgentNode.do_Process: 3
r = 103
terminal = List(3)
G3Publish.do_Process
G3Context.send
lookup = [compute], Some(org.goldenport.g3.G3AgentNode@1d01844a)
G3Pipe.do_Process1(class org.goldenport.g3.G3AgentNode):List(4)
G3Pipe.do_Process2(class org.goldenport.g3.G3AgentNode):4/List()
G3AgentNode.do_Process: 4
r = 104
terminal = List(4)
G3Publish.do_Process
G3Context.send
lookup = [compute], Some(org.goldenport.g3.G3AgentNode@1d01844a)
G3Pipe.do_Process1(class org.goldenport.g3.G3AgentNode):List(5)
G3Pipe.do_Process2(class org.goldenport.g3.G3AgentNode):5/List()
G3AgentNode.do_Process: 5
r = 105
terminal = List(List(101, 102, 103, 104, 105))
terminal = List(5)
[info] == run ==
[success] Successful.
[info]
[info] Total time: 2 s, completed 2010/04/10 6:49:13
TwitterScan3結果
> run org.goldenport.g3.app.TwitterScan3
[info]
[info] == copy-resources ==
[info] == copy-resources ==
[info]
[info] == compile ==
[info] Source analysis: 0 new/modified, 0 indirectly invalidated, \
0 removed.
[info] Compiling main sources...
[info] Nothing to compile.
[info] Post-analysis: 257 classes.
[info] == compile ==
[info]
[info] == run ==
[info] Running org.goldenport.g3.Main \
org.goldenport.g3.app.TwitterScan3
G3Pipe.do_Process1(class \
org.goldenport.g3.G3StartNode):List(WrappedArray(org.goldenport.g3.app.TwitterScan3)) \
G3Pipe.do_Process2(class \
org.goldenport.g3.G3StartNode):WrappedArray(org.goldenport.g3.app.TwitterScan3)/List() \
G3StartNode.do_Process: \
WrappedArray(org.goldenport.g3.app.TwitterScan3)
G3Invoke.do_Process
G3Context.invoke
lookup = [demogon], \
Some(org.goldenport.g3.G3ServiceNode@53015c53)
G3Pipe.do_Process1(class org.goldenport.g3.G3ServiceNode):List()
G3Pipe.do_Process2(class \
org.goldenport.g3.G3ServiceNode):List()/List()
G3ServiceNode.do_Process: List()
2010/04/10 6:44:21 \
org.apache.http.client.protocol.ResponseProcessCookies \
processCookies
?x??: Invalid cookie header: "Set-Cookie: guest_id=1270849461120; \
path=/; expires=Sun, 09 May 2010 21:44:21 GMT". Unable to \
parse expires attribute: Sun, 09 May 2010 21:44:21 GMT
terminal = List(<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" \
xmlns:georss="http://www.georss.org/georss" \
xmlns="http://www.w3.org/2005/Atom">
<title>Twitter / demogon</title>
<id>tag:twitter.com,2007:Status</id>
<link type="text/html" href="http://twitter.com/demogon" \
rel="alternate"/>
<link type="application/atom+xml" \
href="http://twitter.com/statuses/user_timeline/demogon.atom" \
rel="self"/>
<updated>2010-04-09T21:44:21+00:00</updated>
<subtitle>Twitter updates from \
出茂権太郎 / \
demogon.</subtitle>
<entry>
<title>demogon: \
自由が丘についた。レストランがいい。</title> \
<content type="html">demogon: \
自由が丘についた。レストランがいい。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554547226</id>
<published>2010-02-24T01:56:05+00:00</published>
<updated>2010-02-24T01:56:05+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554547226" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
<entry>
<title>demogon: \
やっぱり自由が丘のイタリアンなんかどう。</title> \
<content type="html">demogon: \
やっぱり自由が丘のイタリアンなんかどう。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554480122</id>
<published>2010-02-24T01:54:33+00:00</published>
<updated>2010-02-24T01:54:33+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554480122" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
<entry>
<title>demogon: \
武蔵小杉に着いた。一杯やろう。</title> \
<content type="html">demogon: \
武蔵小杉に着いた。一杯やろう。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554430782</id>
<published>2010-02-24T01:53:26+00:00</published>
<updated>2010-02-24T01:53:26+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554430782" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
</feed>
)
G3Pipe.do_Process1(class org.goldenport.g3.G3Agent):List(<?xml \
version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" \
xmlns:georss="http://www.georss.org/georss" \
xmlns="http://www.w3.org/2005/Atom">
<title>Twitter / demogon</title>
<id>tag:twitter.com,2007:Status</id>
<link type="text/html" href="http://twitter.com/demogon" \
rel="alternate"/>
<link type="application/atom+xml" \
href="http://twitter.com/statuses/user_timeline/demogon.atom" \
rel="self"/>
<updated>2010-04-09T21:44:21+00:00</updated>
<subtitle>Twitter updates from \
出茂権太郎 / \
demogon.</subtitle>
<entry>
<title>demogon: \
自由が丘についた。レストランがいい。</title> \
<content type="html">demogon: \
自由が丘についた。レストランがいい。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554547226</id>
<published>2010-02-24T01:56:05+00:00</published>
<updated>2010-02-24T01:56:05+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554547226" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
<entry>
<title>demogon: \
やっぱり自由が丘のイタリアンなんかどう。</title> \
<content type="html">demogon: \
やっぱり自由が丘のイタリアンなんかどう。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554480122</id>
<published>2010-02-24T01:54:33+00:00</published>
<updated>2010-02-24T01:54:33+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554480122" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
<entry>
<title>demogon: \
武蔵小杉に着いた。一杯やろう。</title> \
<content type="html">demogon: \
武蔵小杉に着いた。一杯やろう。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554430782</id>
<published>2010-02-24T01:53:26+00:00</published>
<updated>2010-02-24T01:53:26+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554430782" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
</feed>
)
G3Pipe.do_Process2(class org.goldenport.g3.G3Agent):<?xml \
version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" \
xmlns:georss="http://www.georss.org/georss" \
xmlns="http://www.w3.org/2005/Atom">
<title>Twitter / demogon</title>
<id>tag:twitter.com,2007:Status</id>
<link type="text/html" href="http://twitter.com/demogon" \
rel="alternate"/>
<link type="application/atom+xml" \
href="http://twitter.com/statuses/user_timeline/demogon.atom" \
rel="self"/>
<updated>2010-04-09T21:44:21+00:00</updated>
<subtitle>Twitter updates from \
出茂権太郎 / \
demogon.</subtitle>
<entry>
<title>demogon: \
自由が丘についた。レストランがいい。</title> \
<content type="html">demogon: \
自由が丘についた。レストランがいい。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554547226</id>
<published>2010-02-24T01:56:05+00:00</published>
<updated>2010-02-24T01:56:05+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554547226" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
<entry>
<title>demogon: \
やっぱり自由が丘のイタリアンなんかどう。</title> \
<content type="html">demogon: \
やっぱり自由が丘のイタリアンなんかどう。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554480122</id>
<published>2010-02-24T01:54:33+00:00</published>
<updated>2010-02-24T01:54:33+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554480122" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
<entry>
<title>demogon: \
武蔵小杉に着いた。一杯やろう。</title> \
<content type="html">demogon: \
武蔵小杉に着いた。一杯やろう。</content> \
<id>tag:twitter.com,2007:http://twitter.com/demogon/statuses/9554430782</id>
<published>2010-02-24T01:53:26+00:00</published>
<updated>2010-02-24T01:53:26+00:00</updated>
<link type="text/html" \
href="http://twitter.com/demogon/statuses/9554430782" \
rel="alternate"/>
<link type="image/png" \
href="http://s.twimg.com/a/1270842741/images/default_profile_5_normal.png" \
rel="image"/>
<author>
<name>出茂権太郎</name>
</author>
</entry>
</feed>
/List()
content = List()
content = List(demogon: ???R???u???????B???X?g???????????B)
xxx = demogon: ???R???u???????B???X?g???????????B
AtomContent = List(demogon: ???R???u???????B???X?g???????????B)
content = List(demogon: ???????R???u??C?^???A????????B)
xxx = demogon: ???????R???u??C?^???A????????B
AtomContent = List(demogon: ???????R???u??C?^???A????????B)
content = List(demogon: ????????????????B??t????B)
xxx = demogon: ????????????????B??t????B
AtomContent = List(demogon: ????????????????B??t????B)
G3Pipe.do_Process1(class \
org.goldenport.g3.G3Agent):List(<feed><id>tag:twitter.com,2007:Status</id><title>Twitter \
/ demogon</title><updated>Sat Apr 10 06:44:21 JST \
2010</updated><entry><title>demogon: \
???R???u???????B???X?g???????????B</title><link/><link/><content>demogon: \
\
???R???u???????B???X?g???????????B</content></entry><entry><title>demogon: \
\
???????R???u??C?^???A????????B</title><link/><link/><content>demogon: \
\
???????R???u??C?^???A????????B</content></entry><entry><title>demogon: \
????????????????B??t????B</title><link/><link/><content>demogon: \
????????????????B??t????B</content></entry></feed>)
G3Pipe.do_Process2(class \
org.goldenport.g3.G3Agent):<feed><id>tag:twitter.com,2007:Status</id><title>Twitter \
/ demogon</title><updated>Sat Apr 10 06:44:21 JST \
2010</updated><entry><title>demogon: \
???R???u???????B???X?g???????????B</title><link/><link/><content>demogon: \
\
???R???u???????B???X?g???????????B</content></entry><entry><title>demogon: \
\
???????R???u??C?^???A????????B</title><link/><link/><content>demogon: \
\
???????R???u??C?^???A????????B</content></entry><entry><title>demogon: \
????????????????B??t????B</title><link/><link/><content>demogon: \
????????????????B??t????B</content></entry></feed>/List()
==> <feed><id>tag:twitter.com,2007:Status</id><title>Twitter / \
demogon</title><updated>Sat Apr 10 06:44:21 JST \
2010</updated><entry><title>demogon: \
???R???u???????B???X?g???????????B</title><link/><link/><content>demogon: \
\
???R???u???????B???X?g???????????B</content></entry><entry><title>demogon: \
\
???????R???u??C?^???A????????B</title><link/><link/><content>demogon: \
\
???????R???u??C?^???A????????B</content></entry><entry><title>demogon: \
????????????????B??t????B</title><link/><link/><content>demogon: \
????????????????B??t????B</content></entry></feed>
terminal = \
List(<feed><id>tag:twitter.com,2007:Status</id><title>Twitter \
/ demogon</title><updated>Sat Apr 10 06:44:21 JST \
2010</updated><entry><title>demogon: \
???R???u???????B???X?g???????????B</title><link/><link/><content>demogon: \
\
???R???u???????B???X?g???????????B</content></entry><entry><title>demogon: \
\
???????R???u??C?^???A????????B</title><link/><link/><content>demogon: \
\
???????R???u??C?^???A????????B</content></entry><entry><title>demogon: \
????????????????B??t????B</title><link/><link/><content>demogon: \
????????????????B??t????B</content></entry></feed>)
[info] == run ==
[success] Successful.
[info]
[info] Total time: 2 s, completed 2010/04/10 6:44:22