2007年12月27日木曜日

JRuby idioms

* Java を使う

- require 'java'
- include_class 'java.lang.String' to short name access
- java.lang.String.new("abc")

* File I/O

- read

f = open(filename)
while line = f.readline
:
end
f.close


begin
line = readline
rescue EOFError
break
end

2007年12月26日水曜日

Google Chart API

Google Chart API の整理

もっとも、Eastwood のためだが...

- user 1日 50000 リクエストまで。

http://chart.apis.google.com/chart?
chs=200x125
&chd=s:helloWorld
&cht=lc
&chxt=x,y
&chxl=0:|Mar|Apr|May|June|July|1:||50+Kb

- chs=wwwxhhh は pixel 単位のサイズ
- chd=.... はデータ
- cht=... はチャートの種類
- chxt=x,y は x, y 両方のラベルが必要ということを指定
- chxl=... は x, y 軸のラベル

- HTML に embed するときは & ではなく & をつかう。

- char data には3種類のエンコーディングがある。
-- Simple 62 までの値 chd=s:...
A=0,B=1,Z=25,a=26,z=51,0=52,9=61,_=missing value
data set separator=","
-- Text 1000 までの値 chd=t:...
0.0=0,1.0=1,100.0=100, -1=missing value
data set separator="|"
-- Extended 4096 までの値 chd=e:
use char pair, A-Za-z0-9-._
AA = 0, AZ = 25, Aa = 26, Az = 51, A0 = 52, A9 = 61, A- = 62, A. = 63
BA = 64, BZ = 89, Ba = 90, Bz = 115, B0 = 116, B9 = 125, B- = 126, B. = 127
.A = 4032, .Z = 4057, .a = 4058, .z = 4083, .0 = 4084, .9 = 4093, .- = 4094, .. = 4095.
'_' = missing value
data set separator=","

(書きかけ...)

NetBeans 6 / ruby gems OutOfMemoryError

Java heap size はどうもハードコーディングされているらしい。

http://deadlock.netbeans.org/fisheye/rdiff/netbeans?csid=MAIN:mkrauskopf:20071216155725&u&N

Index: ruby/platform/src/org/netbeans/modules/ruby/platform/RubyExecution.java
===================================================================
RCS file: /cvsup/nb_all/ruby/platform/src/org/netbeans/modules/ruby/platform/RubyExecution.java,v
diff -u -N -r1.2 -r1.3
--- ruby/platform/src/org/netbeans/modules/ruby/platform/RubyExecution.java 16 Dec 2007 15:48:05 -0000 1.2
+++ ruby/platform/src/org/netbeans/modules/ruby/platform/RubyExecution.java 16 Dec 2007 15:57:25 -0000 1.3
@@ -170,7 +170,7 @@

String extraArgs = System.getenv("JRUBY_EXTRA_VM_ARGS"); // NOI18N

- String javaMemory = "-Xmx256m"; // NOI18N
+ String javaMemory = "-Xmx512m"; // NOI18N
String javaStack = "-Xss1024k"; // NOI18N

if (extraArgs != null) {

JRUBY_EXTRA_VM_ARGS に -Xmx512m を指定することでこれは解決。

rake がなかなか動いてくれない。以下のキーワードで探してみるが、
これといったのが見つからない...

"adding Java library jruby-complete-1.0.2" "rake aborted!" "execution expired"

何とか war ファイルはできたものの、アクセスするとディレクトリリストが
見えてしまう。アプリケーションとしては動かない。rake task で run すると
jetty が起動されるが、JSP サポートがないと出る。
ただ、war をデプロイしたのは Tomcat 5.5.1 だ。なぜだ???

2007年12月21日金曜日

Scala

Java Posse の Martin Odersky の interview から、Scala の作者である
だけではなく 1.3 以降の javac の開発もやってきた人だと関心。Scala
自身は初見だったが、よく pod cast にでてきたのは覚えている。言語に
うるさい人には気になるようだ。

Scala のコンパイラ、実行環境はオープンソースでダウンロードできて、
1.4 あたりからの java があれば実行できる。

* Hello World

package hello;
object HelloWorld {
def main(args: Array[String]) {
println("Hello World!")
}
}

- package は java と同様
- object Name { ... } は Name というシングルトンを作る
- メソッドの定義は def ではじめる。引数は "名前: 型" で宣言する
- println は組み込み
- import も同様に使えるが、機能が拡張されている。最後の要素で
{class1, class2} のようにまとめて指定でき、import a.b.C._ で
C がクラス名とすると、これは C に関する static import として
働く。

- ソースの拡張子は .scala, scalac でコンパイル。ファイル名とクラス名の
 一致の必要はないようだ。

* クラス定義

class Complex(real: double, imaginary: double) {
def re = real
def im = imaginary
override def toString() =
"" + re + (if (im < 0) "" else "+") + im + "i"
}

クラス名のあとに引数のリストが来る。これは primary constructor の
シグネチャで、class の body がパースされる。ボディがパースされるのは
ruby に似ている。

def re = real

は初期値の設定と re という getter/setter の宣言でもある。プロパティを
作っているといってもいいかも知れないが、うるさい人は色々と意見がある
だろう。本当のプロパティはコンポーネントモデルにおけるプロパティであり、
参照、設定のほかにもイベント機能なども備えないとなど云々...

Ruby のように自明なものは関数のあとに () を書かなくても呼べる。
またオブジェクトのオペレーションを呼ぶときに "." すら省略できるケースが
ある。

インスタンス化は java とほぼ同じ。

val c = new Complex(1.2, 3.4)

これは厳密に書けば

val c: Complex = new Complex(1.2, 3.4)

* Generics / Genericity

Generics/Template 相当の機能を備えている。Genericity と呼んでいる。
下の例では a は任意の型。

class Reference[a] {
private var contents: a = _
def set(value: a) { contents = value }
def get: a = contents
}

* Mixin 機能。

Ruby のものと似ている。AOP の手法の一つともいえる。実態つき、拡張可能な
インターフェイスのようなものと言ってもいい。

* call-by-value/call-by-name

関数呼び出しは call-by-value と call-by-name があり、引数の評価の
仕方が異なる。デフォルトは call-by-valude であるが、reduction が
完了しない事がある。その場合にはパラメータの型の前に => を入れると
call-by-name になる。

def constOne(x: Int, y: => Int) = 1

* if-else は conditional expression の様にも使える。

def abs(x: Double) = if (x >= 0) x else x

* Unit は java の void とほぼ同様。()

* Nested function

inner class の様に関数の中に関数を定義できる。一番外側の関数の変数は
nested function からも参照できる。

* Tail Recursion

一見、再起呼び出しに見えても、スタックを余計に消費しないように実行できる
場合はそうしてくれる。

* First-Class Functions

関数は first-class value と呼ばれ、他の関数に渡すことができる。そのような
関数を受け取ったり、返したりする関数は higher-order functions と呼ばれる。

関数のパラメータの型は "Int => Int" (Int をとり Int を返す) という形で
指定できる。その例として下のものは a から b の間の値に f 適用してその
合計をとる関数となる。

def sum(f: Int => Int, a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f, a + 1, b)

def sumInts(a: Int, b: Int): Int = sum(id, a, b)
def sumSquares(a: Int, b: Int): Int = sum(square, a, b)
def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b)

def id(x: Int): Int = x
def square(x: Int): Int = x * x
def powerOfTwo(x: Int): Int = if (x == 0) 1 else 2 * powerOfTwo(x 1)

2007年12月20日木曜日

J2EE 1.4

J2EE 1.4 で iBATIS を使った Bean Managed Entity Bean のサンプルを作ることに
なった。一つ一つ手で行うのは無謀なので NetBeans6 を使ってみる。

J2EE 1.4 なので以下の URL を参考にする。
http://www.netbeans.org/kb/41/
http://www.netbeans.org/kb/41/j2ee-tut/index.html

SavingsAccount のサンプルで Bean Managed Bean を作ってみる。Bean Module を
作り、Entity Bean を追加する。Entity Bean 内で Enterprise Resource ->
Use Database でデータベースを選択することになるが、サンプルは NetBeans4.1
ベースで当時のバンドルデータベースは pointbase で細かなところが違って
くる。

Use Database のダイアログでまず最初に指定するのは Reference Name だが、
これは app server ごとに異なる sun-ejb-jar.xml の中で JNDI で参照する
サーバのデータベースリソース (jdbc/mysqlTest01 等) につける名前だ。
この設定は NetBeans が勝手にやってくれる。選択対象は Sun Java System
Application Server Admin Console の Resources/JDBC/JDBC Resources の
エントリから選択することになる。このページには jdbc/* がリストされている。
これらのエントリは個々に enable/disable ができて Resources/JDBC/Connection Pools
のエントリを参照している。Connection Pools のエントリはいわゆるデータ
ソースで URL, user, JDBC driver 等の属性を持っている。PointBase を
復習するのも面倒なので MySQL を使ってみる。ウィザードを使えば設定は
比較的簡単だが、最初 XA driver を選んでしまい、トランザクション関連の
エラーになったので、ただのデータソースにした。コネクションプールに
対応した JDBC Resource も定義して、Entity Bean からは適当に名前を
つけたリソースを参照させる。

実際の DB ソーサのコードはベタな JDBC なのでサンプルからコピー。
ビジネスメッソッドもコンテキストメニューを使ったり、リファクタリングの
フィールドのエンカプセレイト機能を使って作っていく。ビジネスメソッドは
対応するものが *Remote.java のインターフェイスに定義されていなければ
ならないが、IDE が 'throws RemoteException;' を自動的につけてくれて
いないメソッドについては実行時にエラーが出たので、手でつけた。

Home メソッドも追加していくことになるが、コンテキストメニューで追加すると
Bean には ejbFindByLastName のようなメソッドができるが、戻り値を複数に
指定しておくとどうやら Home インターフェイス側には cByLastName のような
メソッドができる。コレクションで返すのでこういうネーミングになっているのかも
と勝手に納得していたが、そういうことではないらしい。名前はあっていないと
いけない。インターフェイスにあわせて ejbCByLastName とやってもだめ、
ejbcByLastName とやってもだめだった。Collection を返すことが名前から
わかることは悪いことではないと思い、Home 側を findcByLastName として
Bean 側を ejbFindcByLastName とすると動いた。この辺は Java Beans の
細かなところを調べればわかるのかも知れないが、その気力はない。
経験則としてキャメルケース・パスカルケースに1文字のワードというか、節を
持たせるのは良くないということを覚えておこう。

これくらいをクリアしたところで動くようになった。サンプルのクライアントで
一箇所だけ動かなかったのは remove の呼び出し。そのままでは文法エラーに
なるし、home 経由で呼ぼうとしてもエラーが消えない。今回はスキップ。


次に Roster のサンプルで CMP も確認しておく。このケースではもともと
関連のあるテープルを定義しておいて、それから New -> CMP Entity Beans from
Database... で作っている。若干強引に MySQL 上にテーブルを作ってこの処理を
すると関連のテーブルだけプライマリキーがないということで Bean が
作成されない。alter table _table_name_ add constraint primary key (field, field1,...)
で強引にやると作成されたが、ejb-jar.xml に CMP Relationships がまったく
現れない。

結局 Derby でテーブル作成の SQL が通ったので、それをもとにやってみると
動いたみたい。1:N や M:N の参照をわかりやすい名前に ejb-jar.xml で変更する
とそれがソースに反映されるとあったが、どうやらこれは動いていない。

次のステップとしていくつかの Bean に finder メソッドを EJB QL で追加して
行くところだが、このあたりは NB 4.1 と 6.0 の違いが大きいようで、このあたりで
今日は断念。

やっぱり、昔の EJB は面倒くさい...

2007年12月9日日曜日

Xcode

自作の C++ アプリケーションのリファクタリングの為に NetBeans6 に取り込んでみる。
その過程でコンパイラを聞かれるがデフォルトではLeopard にはコンパイラはないらしい。
(cc, c++ は not found になる。)Google を見て回ったところ Xcode というパッケージに
含まれているようだ。ユーザー登録をすれば ADC からダウンロードできるとのこと。
ユーザー登録の際に Apple ID とリンクできるようなことが書いてあったので、登録して
みると確認等の画面で日本語が文字化けしている。まあいいだろうということでXcode 3.0
をダウンロード。ディスクイメージをマウントしてみて出てきた PDF をみてみると
Leopard のメディアにも入っているらしいということが判明...

展開したものから XcodeTools.mpkg を入れてみる。特に問題なくインストール完了。


Macintosh:wtp$ cc
i686-apple-darwin9-gcc-4.0.1: no input files
Macintosh:wtp$ c++
i686-apple-darwin9-g++-4.0.1: no input files

2007年11月22日木曜日

Leopard

Mac mini が届いた。が、気づいたらキーボードがPS2 だった。
翌日Apple keyboard を購入してやっと起動。ムービーが流れて、
ユーザー登録から始まる。まだTiger だ。
Leopard の DVD? を入れてアップグレード。難なく終わった。

Spaces はデフォルトでオフなので、オンにしたが F8 がきかない。
Apple keyboard では F1-F12 まではほかの機能に割り当てられていて
ファンクションキーとして動かすには fn と同時に押す必要が
あるようだ。でも、それでは面倒なので起動は F13 にふってみたが、
動作がどうも見覚えのあるのと違う。4つの小窓が出てきて、矢印も
出てきてびゅんびゅんと切り替わるというイメージだったが、どうも
地味だ。後でわかったが ctrl+矢印でそのような動作になる。
築かなかったらフリーソフト探しまくってたかも...

Mail で IMAP 接続できるか試してみるが、これには SSL 機能は
見当たらない。あきらめかけたところで、Thunderbird を試して
みる。なんか、うまくいった。ただ、パスワードを覚えさせて
しまって、それがどこに行ったか気になった。OS X のキーチェーン
を調べても Thunderbird のエントリはないし... どうやら Thunderbird
自身が保持しているようだが、詳細は今日のところはあきらめた。

Boot camp で既存ボリュームのリサイズができるか気になっていた
ので試してみたが、問題ないようだ。

Parallels も購入しておいたので入れてみる。最初の起動でプロダクト
キーを入れたら、アップデート版の通知がでる。アップデートすると
もう一度プロダクトキーを要求された。

マニュアルが厚めだったので、かまわず直感でやってみる。
ゲストOS に見せるメモリサイズや、ディスクサイズなどの設定は
一番詳しい(一番下)のモードを選ぶ必要がありそう。

Solaris 10 を入れてみた。やはり I/O がホストOS 経由のせいか
直接ディスク入れるときより遅い気がする。はたと気づくと Parallels
のウィンドウがない。ただ、プロセスとしては存在しているようだ。
このとき、ほとんど操作ミスで画面のスクリーンショットをとった
のだが、そこにはコンソールモードでの問い合わせメッセージが
でている。NFS のドメインがなんたらというやつだ。

よくわからなかったので、強制終了して Lepard も再起動。Solaris 10
は起動中にいわゆるシングルユーザーモードで止まってしまった。
インストールが完了していないということだろう。

いったん消して、再度インストールしてみる。右側のタブに全画面表示
があったので、今度はそのモードでインストール。alt-enter で全画面と
通常を行き来できる。VMWare などと同じでいったんゲストの画面に
マウスポインタが移ると ctrl-alt しないと OS X にもどらない。

インストール完了、GUI ログインも出てくる。が、画面がでかい。
xwininfo -root でみると 1600x1200 になっている。Parallels の
編集/仮想マシン、、、で画面サイズを変更しても反映されない。
これは xorgcfg でディスプレイのサイズを低い解像度にすることで
解決できた。

次はネットワークだが、どうも Solaris からは見えていない。SMC
などで DHCP の設定などないか探してみるが見当たらない。Solaris との
ファイル共有はできないので、ファイル転送はネットワークしかないのだが...

Google をサーチすると手順が見つかった。/Library/Parallels/Tools/vmtools.iso
をCD/DVD デバイスにして Solaris を立ち上げると、このイメージがマウント
されているので、その中にある solaris 用の network.sh を実行して、
DHCP のクライアントになるかに yes と答えるだけだ。どうやら、ここの
部分は Parallels 側から提供されていて、インストール時点では
ネットワークは全くないことになっているようだ。

あがってしまえば ssh, scp で操作はできる。

ちょっとじたばたしたが、結構いい感じ。

2007年11月20日火曜日

Ant notes

Ant の覚え書き

ファイルからプロパティをロードするには次の要素を設定しておく。


<property file="build.properties"/>


build.properties には key = value を書いておく。
build.xml からは ${key} で参照可能。

あまり真剣に書いたことがなかったが、Java プログラムの起動に引数が
たくさんつくケースのために java タスクを使ってみる。結果、次のような
物に落ち着いた。


<target name="run_pja" depends="compile" description="run">
<java classname="test" fork="true">
<classpath>
<pathelement location="${jcaptcha.jar_path}"/>
<pathelement path="."/>
</classpath>
<jvmarg value="-Xbootclasspath/a:${pjajar}"/>
<jvmarg value="-showversion"/>
<sysproperty key="awt.toolkit" value="com.eteks.awt.PJAToolkit"/>
<sysproperty key="java.awt.graphicsenv"
value="com.eteks.java2d.PJAGraphicsEnvironment"/>
<sysproperty key="java2d.font.usePlatformFont" value="false"/>
<sysproperty key="java.awt.fonts" value="${jh}/jre/lib/fonts"/>
<sysproperty key="user.home" value="${pja_home}/lib"/>
</java>
</target>


fork="true" をしてしているのは jvmarg は fork="true" でのみ有効だから。

-Dkey=value は <sysproperty key="..." value="..."/> を羅列すれば
良いらしい。<syspropertyset .../> は使っていた版で java task ない
ではサポートされていないと出たので今回は見送る。

2007年11月16日金曜日

Technologies for SOA

SOA!!!



Sun Tech Days で SOA 関連のセッションで紹介されていた BPEL など SOA
関連の技術が思っていたよりわかりやすかった。また、NetBeans 6 ではその
開発を補助する機能がそろっているという事でチュートリアルをみながら
試してみた。

以前、Axis を活用しようと思ったときに、XML Schema や WSDL の手書きに
ウンザリしたので、少し敬遠していたけれど、NB6 ではこれらのファイルも
IDE の管理下で作れるらしい。

チュートリアル概要



HelloWorld は単純すぎるので Loan のサンプルの概要を書いておく。

BPEL モジュールの作成


New Project > SOA > BPEL Module で作成できる。

  • XML Schema の作成

    サービス呼び出しの際に簡単な文字列をひとつ渡すだけであれば、これは
    おそらく必要がない。実際には何らかのデータ構造を渡すことになるであろうし、
    それには、それなりの型を持たすことがわかりやすい。そうするためには XML
    Schema で complex type を定義することになる。



    実際の操作は画面右側のパレットから Complex Type を Editor の Complex Types
    のところにドロップすることで型が作れる。さらにそれぞれの型に Element icon
    をドロップして要素を作っていく。



    もうひとつ行うことは Complex Type を決めてから、それらをグローバルエレメントに
    登録すること。やり方は Element icon を Editor の Elements のところにドロップ
    して名前をつけて、Definition で Complex Types に作った型の名前をセットする。


  • WSDL の作成

    Process Files の下に WSDL document を作成する。独自の XML Schema を使う場合には
    Import XML Schema File(s) チェックボックスをチェックして先に定義したものや、
    ネームスペースを利用して、インポートできる。



    次は Editor の Partner タブでメッセージの名前や、型を決める。In/Out の最低2つは
    あるので、リクエストの名前をわかりやすいものに変え、型を決める。型はダイアログの
    中から選ぶだけなので簡単。XML Schema をインポートしておけばその中で決めた型を
    引数の型に使える。この際の型の名前は complex type の名前ではなく Elements に
    登録した名前になる。IDE が選択肢を示してくれるので簡単だが、うろ覚えで手書きだと
    とてもはまるかも知れない...



    オプショナルで LoanProcessor EJB モジュールを作る。ユーザー情報をもとに Loan の
    可否を判定する。必然的に Web Service のインターフェイスを持つことになる。
    Web Service のフォルダを右クリックして Web Service を作れる。そのあと、その
    Web Service を右クリックして Add Operation で操作を追加する。その際にパラメータも
    定義する。結果として @WebService アノテーションを使った java ソースができる。
    作成時に Session Bean にデリゲートすることもできるようだ。
    本当に EJB じゃないといけないのかと疑問に思った。なぜなら EJB Container が
    前提といわれると困るから。結果として、これは杞憂。できたのは本当にクラスを
    まとめただけの jar ファイルだった。wsdl もこの時点では存在しない。



  • BPEL process の作成

    Process Files に BPEL Process を作るとフローチャートのような画面が現れる。
    まずはここに入力として request の wsdl, Loan のチェックを行う web service
    を登録する。後者に関しては wsdl は自動生成されるようだ。このステップは
    モジュールのドラッグでできる。



    この次のステップとして、receive, invoke, reply をパレットからドラッグして、
    サービスと関係付けていく。プロセスの最初は、receive で始まる。リクエスト待ちの
    先頭というわけだ。



    Assign 要素で変数を作る。関連づけは BPEL Mapper でソースとデスティネーションを
    つなぐだけだ。




  • Composite Application の作成

    別プロジェクトとして Composite Application を作る。この定義ファイルは *.casa.
    この JBI モジュールとして、作成した BPEL module をドラッグ&ドロップで登録。



    これに consumer としての SOAP アダプターを登録する。



  • テストの作成、登録

    composite application の Test folder にテストを作れる。リクエストのパラメータを
    埋めるだけでテストになる。1回目の実行結果が正しい実行結果とされ、以後のテストと
    比較される。結果を消す、クリアしてしまえば正しいテスト結果を変えられるということか?


  • JBI とは

    NB6 の Composite Application が JBI の実装ということかなと思う。JSR 208 という
    事だが、これには IBM, BEA は賛同していないらしい。BPEL まではいいが、その上は
    まだ議論の余地があるということか....ということはこれらのベンダのBusiness Process
    Integration は propretary ???


2007年10月3日水曜日

ruby misc tips

Gem での proxy 超えは http_proxy 環境変数に http://_proxy_host_:_port_ を
設定するのが良いらしい。

rake を初めてビルドツールとして使ってみる。利点は make/ant に比べて
rakefile の記述力が高いということだろうか。慣れると面白そう。
http://www2s.biglobe.ne.jp/~idesaku/sss/tech/rake/

Capistrano も気になって少し調べてみる。こちらはデプロイツールとなっている。
複数のホストにまたがる更新処理などを書きやすいということのようだ。
古い版は Rails に依存していたのでレシピファイルは config/deploy.rb だが
現行の v2.0.0 では Capfile または capfile も受け付ける。

$ gem install capistrano --include-dependencies

ssh が使えて posix shell 相当のものがデフォルト(?)の場所にあるシステム
に対していろいろと実行を指示出来るようである。

ssh が使えてというのは capistrano を実行するシステムの ssh public key が
リモートのシステムの authorized_keys に登録された状態をいう。
手順としては ssh-keygen -t dsa で private/public キーを作り、public キー
をログイン先の .ssh の authorized_keys に追加する。クライアントからは
ssh リモートホスト だけでログインできるようにしておく。一回目は known_hosts
更新があるので登録するかどうか聞かれるので、登録しておく。private キーを
暗号化した場合には ssh でリモートアクセスする際に、クライアントサイドで
private キーを使用するために暗号化に使用したパスワード(パスフレーズ?)を
聞かれる。このケースはよく試していないが capistrano からでもターミナルで
インターラクティブに実行している分には問題なさそう。

Cygwin に OpenSSH を入れれば SSH サーバとして構成できるようで (ssh-host-config
を一度実行する必要がある、また Cygwin 自体 all user 対象でインストールし、かつ
アドミン権限が必要)サービスを起動しておけば ssh で Windows マシンにログイン
できる。結局のところ Cygwin 環境にリモートで入るわけで Linux より少し
不便な環境ぐらいに思ったほうが良いだろう。

Capistrano 自体はまだまだ学習しないといけないが、task にどのホストで実行
させるかという属性がつけられる。また、単一、複数のほすとを role として
定義し、role に対して特定のタスクを実行などということもできる。
http://www.capify.org/

2007年10月2日火曜日

rails again

Linux で Ruby on Rails 環境を確保。

サービスの設定に mysqld があるので、起動してみると動いたみたい。

さて、パスワードはなんだ??? 管理ユーザは root なのか???

mysqld は --skip-grant-tables オプションつきで起動すると
権限不要モードで立ち上がる。その状態で mysql mysql で接続して
次のように root のパスワードをクリアできる。

mysql> update user set Password=null where Host='localhost' and User='root';

どうやら RedHat についてくる mysql はこの状態になっている。
(したがって上記は不要)

使える状態にするため root にパスワードを設定する。

# mysqladmin --user=root password <newpass>

なければデータベースを作る

mysql > create table test;

アプリケーション用のユーザーを作る
mysql > grant all privileges on test.* to test@localhost identified by '...';

一応、作成したユーザーでローカルアクセスできるかを確認。
$ mysql -u test -p test
Password:
mysql> show tables;

Rails のインスタンスを作成
$ rails test1

当面は development 部分だけでよいが database 設定を行う(user, password, etc)
$ vi config/database.yml

ちなみに local 接続のソケットはデフォルトが /tmp/mysql.sock になっているようなので
sock: /var/lib/mysql/mysql.sock の一行を入れて適切に変更。このパスは ps -ef | grep mysql
で見つけた。

まずはモデルの作成。

$ ruby script/generate model Book
...
create db/migrate/001_create_books.rb

db/migrate/001_create_books.rb を編集してフィールドを定義
create_table の do block 内にカラムを名前、型で定義。
これで sql を打たなくてもテーブルが作れる。

class CreateBooks < ActiveRecord::Migration
def self.up
create_table :books do |t|
t.column :isbn, :string
t.column :name, :string
t.column :author, :string
t.column :manufacturer, :string
t.column :release_on, :date
end
end

def self.down
drop_table :books
end
end



$ rake migrate
// 実はここで socket がおかしいことに気づいた。

$ rake migrate
== CreateBooks: migrating ====...
-- create_table(:books)
-> 0....
== CreateBooks: migrate (0....s) ===

The rake task migrate has been deprecated, please use the replacement
version db:migrate

メッセージは db:migrate を今後は使いなさいとのこと。

ここで rake と打つとテストをしてくれるらしいが socket のエラーで失敗する。
test 以下のファイルを眺めていると、結局 config の下のファイルに行き着く。
database.yml には test セクションがあり、そこはデフォルトのままだったので
db name, user, pass, socket をなおす。このあとは rake は動作するようになった。

あとは scaffold を Book に対して行えばとりあえず CRUD はできるようになる。

$ ruby script/generate scaffold Book

$ ruby script/server

validation の例:

$ vi app/models/book.rb

class Book < ActiveRecord::Base
protected
def validate
errors.add('isbn', 'format error') unless isbn =~ /\A[0-9X]+\z/
end
end


DB 抜きで簡単なアプリを作りたければ

$ ruby script/generate controller foo
とすると次のファイルができる。
app/views/foo
app/controllers/foo_controller.rb
test/functional/foo_controller_test.rb
app/helpers/foo_helper.rb

このまま foo にアクセスしても Unknown action と出るだけ。
FooController もからだし、view も空っぽだ。

$ vi app/views/foo/index.rhtml

<html>
<head>
<title>Foo</title>
</head>
<body>
<h2>Foo page</h2>
This is the index page for Foo
</body>
</html>


これでも悪くはないがスタイルの適用を考えれば

app/views/layouts 以下に view の名前で rhtml を作り、app/views/<controller>/*.rhtml
は body の中身だけにすると良い。

$ vi app/views/layouts/foo.rhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>Foo: <%= controller.action_name %></title>
<%= stylesheet_link_tag 'scaffold' %>
</head>
<body>

<p style="color: green"><%= flash[:notice] %></p>

<%= yield %>

</body>
</html>



$ vi app/views/foo/index.rhtml

<h2>Foo page</h2>
This is the index page for Foo

2007年9月7日金曜日

try / finally by jsr/ret (~java1.3)

Java 1.3 までは try/finally を jsr バイトコードで実現していた。
一見、トリッキーだがわかってみれば簡潔にできている気もする。
しかし、jsr バイトコードはベリフィケーションが難しく、使用を
避ける方向にある。1.4 以降の javac コンパイラでは極力使用しない
ようになっている。1.5 開発時には jsr をなくしてしまえという意見も
あったとかなかったとか.

次のような簡単な try / finally を 1.3 javac でコンパイルする。

try {
System.out.println("main in try block");
} finally {
System.out.println("main in finally block");
}

結果と、インラインの説明。

Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String main in try block
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: jsr 20
# finally block のある 20 に jump. この際、次のバイトコードオフセット 11 が
# stack に push される。
11: goto 31
# offset 31 に飛び、メソッドからリターンする。

# 0-14 の間で例外が発生した場合、exception table にしたがってここに
# 制御が移る。
14: astore_1
# 例外の参照を loc[1] に保持
15: jsr 20
# jsr で一旦 finally block に飛ぶ。
# ret 2 はここに返ってくる。例外をスローして終わる。
18: aload_1
19: athrow
# stack 上にある jsr が残したアドレスをローカル、ここでは local[2] にコピー。
20: astore_2
21: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #5; //String main in finally block
26: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: ret 2
# loc[2] にあるオフセットにリターンする
31: return
Exception table:
from to target type
0 14 14 any

2007年9月6日木曜日

bytecodes memo

dup_x1

tos を複製して2つ下にインサート

.., value2, value1 => ..., value1, value2, value1

===
jsr <target off>
次のバイトコードのアドレスをスタックにプッシュして指定された
アドレスに jump する。

===
ret <slot#>
slot# のアドレスに jump

----------
PuTTY - a terminal emulator. If it's lighter than TeraTerm, worth while trying.

2007年9月5日水曜日

svcadm/svcs

IPアドレスの変更を反映させるだけのために Solaris をリブートしたくない。
Solaris 10 ではこのあたりは SMF の管理下にある。

# svcadm restart network/physical

これでできたようだ。

2007年9月4日火曜日

Solaris changing host/network config

あっさりと動いた。

/etc/hostname.<itf> // bge0
<simply put hostname for the itf>

/etc/hosts
<update entry as needed>

/etc/nodename
<node name of the system itself>

/etc/defaultdomain
// did not exist

/etc/defaultrouter
// put default gateway address

/etc/inet/netmasks
<network addr> <mask>

2007年9月3日月曜日

grub chain loading

見よう見まね、行き当たりばったりでつかってきたので、大事なことを知らなかった。

grup から linux も solaris もあげたいとき、solaris の grub を使えば動く
のは知っていて、それが唯一の方法かと勘違いしていた。chain loading を
使うのがどうやら常識のようで...

title Solaris
rootnoverify (hda0,3,a)
chainloader +1

これで solaris のパーティションから solaris をロードできるブートローダ
(Solaris の grub)が起動される。

2007年9月1日土曜日

Solaris 10 again

Solaris 10 u3 をインストール。

システムは PC サーバーだが、余計なインターフェイスがついているのでインストーラ
起動前にドライバアップデートが必要。

GUI モードのインストーラはドライバアップデートを使うとうまくいかないことが
あるらしいので(実際にエラーが発生)、CUI で入れる。Lan も二つあって、
どちらか迷ったがインスタンス番号が少ないほうで進めた。

---

Xvnc は以前ユーザー起動で xdm login できるようにしていたが、そのやりかたが
思い出せない。散々試した挙句、次の方法でいけることがわかった。

vncserver :2 -query localhost

2007年8月7日火曜日

Facelets

http://homepage1.nifty.com/algafield/glove.html を参考にとりあえず
動かしてみようと試みるがこれがなかなか動かない。

myfaces などの jar に dtd が入っていないことに気づく。
更新してみると、今度は jsf が古いために起動しない。

[04/Apr/2007:16:19:14] warning ( 1940): JSF1033: Resource injection is DISABLED.

なんだかんだで動作したが、この手のエラーは大変だ。
dtd をいろいろとコピーしてみたが、なかなか。

WebLogic, Geronimo では動作するが、Tomcat ではなぜか画面が真っ白だ...

2007年8月6日月曜日

JSF

Struts, Spring はそこそこやったので、JSF も使えるようになっておこうと挑戦してみる。
これといったよさげな書籍がなかったり、古かったりで少し億劫になっていた。
Sun の開発ツールで GUI で触っていたが、少しやってみたところで飽きてしまっていた。
Sun One Studio Creator (?) 等ではどうしても画面ががちがちのレイアウトに縛られて
いるように見えてしまったのも興味をそいだ原因かも。

基本的には faces-config.xml で ManagedBean と navigation rule 等を定義、ManagedBean
は名前とクラスメイト、スコープを最低限定義、navigation rule は from view id に
対して navigation-case を指定して、action の結果に応じて進める view を決める。
form-action を明示的に指定する場合はいいのだが、指定しないといつも success が
返るのだろうか...

ManagedBean 自体は POJO のようなものでも動くし、EJB や何らかの integration を
つかって Model を呼び出せる。

View は JSP が前提となるのか、Tiles, Velocity 等が使えるのか、外部のプラグイン
等が必要なのか要調査。

デフォルトでは (NetBeans では) Faces Servlet が /faces/* にマップされている。
実際には直下においた jsp はそのままのパスではアクセスできず、/faces/ をつけると
アクセスできる。というか、パスの変換が行われているようだ。
斜め読みだが WEB-INF の下には(デフォルトでは?)アクセスできないので、
配置の仕方に注意。

.jsp が URL になってしまうのは格好が悪い気がしたが、これは
javax.faces.DEFAULT_SUFFIX パラメータで変更できる。このパラメータを
探していると Facelet, Apache Faces 等の技術を見つける。これらも
時間を見て勉強しよう。

Seasor2 も見はじめていたが、S2JSF というコンポーネントでは View に
JSF を使う。web.xml でだいぶカスタマイズして(これくらいは実プロジェクト
では当然?)使っている。

2007年7月2日月曜日

JSTL & web-app (servlet?) version

web-app_2_3.dtd までしか対応していない app server でテストを行うことが発生。
たいていの環境は web-app_2_4.xsd で動いていたし、NetBeans 5.5 の作る
web.xml もそうなっている。

次のように DTD 指定に書き換えるだけでよさそうと最初は思った。

<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
'http://java.sun.com/dtd/web-app_2_3.dtd'>

動作させるうちにすぐに問題に気がついた。JSTL の c:forEach が効かないのだ。
なんというか、式がそのまま表示されるだけだ。

結果として taglib の宣言を sun.com/ のあとに jsp があるものからないものに
直して動作するようになった。

(A)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

(B)
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

JSTL のページを斜め読みする限り (A) は JSTL 1.1, (B) は JSTL 1.0 の
uri でどうやら式言語の評価方法も異なるようだ。しかも、それがサーブレット
コンテナのバージョンに依存しているということのようである。

確か、以前 2.4 + 1.0 でエラーで悩まされてそのときに (A) の記述を見つけて
そのように直して解決した記憶がおぼろげながらある。逆 2.3 + 1.1 の場合
にはよりわかりにくい状況になるということだ。よく調べたらありそうだが、
JCTL の動作のトレース情報は簡単に出せるのだろうか...

使用している JCTL のライブラリ自体は 1.1 のままでこのような違いがでて
いるのも不思議な感じ。taglib 指定で動作を変え、コンテナの使い方まで
変えてくるのであれば、良くない組み合わせに警告を出してくれると
いいのだが... OpenSource は怖い。

2007年6月21日木曜日

Using user class from JRuby

Java SE API を JRuby から利用する方法はいろいろな所で紹介されている。
変に load_class してしまうことで素性が Java なのか Ruby なのか
わかりにくくなってしまうのは好きではないのでフルパッケージ名で
使用していた。

いざ自分の定義したクラスを使おうとしてみるとうまくいかない。
試行錯誤の結果必要なのは CLASSPATH を適切に設定して load_class
でクラスをロードすることが必要らしい。たとえロードしてもフルパッケージ名
では参照できない。

2007年6月11日月曜日

SimpleFormController

Form を使ったページを作成しようとして昔のソースを見て困った。
ど忘れしている、というかよく覚えていない。

protected ModelAndView onSubmit(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws HttpSessionRequiredException {


command って何だっけ?
答えは config ファイルで設定していた。

<bean id="htmlEscapeFormController" class="yt.uxtool.presentation.HtmlEscapeController">
<property name="commandClass"><value>yt.uxtool.domain.HtmlEscapeEntry</value></property>
<property name="formView"><value>htmlEscapeView</value></property>
<property name="successView"><value>htmlEscapeView</value></property>
</bean>


次のメソッドもオーバーライドしているがなぜやっているのか思い出せない。

protected Object formBackingObject(HttpServletRequest request)
throws Exception {
log.debug("invoke: session[" + request.getSession(false) + "]");

request.setAttribute("htmlEscape", "true");

return super.formBackingObject(request);
}


答えは AbstractFormController の API ref にあった。onSubmit() は bind,
validate にエラーがなかった場合にのみ呼ばれる。そのため、エラーにかかわらず
リクエストプロパティをビューに渡したいときなどに formBackingObject()
でセットしてやるとよい。忘れずに super.formBackingObject() を呼ぶこと。

納得して POJO を作ってみる。int フィールドがいるのだが、validation
は自前でする必要があるのだろうか...

validator は Validator を implement して inject してやればよい。
validator, controller は Errors の参照が渡される場所ではこれに
reject* する事でエラーを登録する。

2007年6月8日金曜日

jruby 1.0 released !!

早速セットアップして作りこんでみる。今までたいした機能を使っていなかったせいか、、
いろんなエラーで戸惑ってしまう。Ruby はもう少しエラーがわかりやすければ
いいんだけど... 行番号が本当の問題からずれていたり(自分でインタープリタを
作ることを考えるとこの部分が簡単でないのはわかるが)、何か、パーサから
そのまま出されたようなエラーは本当にわかりづらい。

Rails でちょっとこったことをやりだすとはじめてみるエラーがブラウザに出るようになった。


We're sorry, but something went wrong.



We've been notified about this issue and we'll take a look at it shortly.


log/development.log にはすこし具体的なエラーが出ているのでこういう時は
こちらからあたりをつけていくしかない。

2007年6月4日月曜日

Threads on Rails

Rails application 上でアプリケーションから独立した処理を設けたくなった。
時間がきたら何かを始めるような、例えばリモートのファイルの更新を調べて
更新があればその変更をローカルに反映させる、といったことがやりたい。

後に http://www.igvita.com/blog/2007/03/29/scheduling-tasks-in-ruby-rails/
で OpenWFEru, BackgrounDRB などのライブラリがあるのを見つけるが、今回は
まず Ruby の Thread でどの程度できるかを確かめたかった。Java でも
このような用途への Scheduler は Quartz などいろいろあったが、たいていの
ことは Thread を拡張して済ますこともできたからである。

Ruby Thread の情報を探していて気になったのは、どうやらこれは Ruby ないの
ユーザースレッドとして実装されているということだ。言い方をかえると OS から
は単一スレッドのプロセスに見えるが、Ruby 内部で自前で処理を切り替えていると
いうことだ。OS のネイティブスレッドにマップされているわけではない。Java
1.1 の頃の懐かしの green thread と同じ原理だ。スレッドのセマンティックは
使えるが、それぞれが本当に平行して走れるわけではないため、計算主体の
処理をスレッド化しても処理時間が短くなるわけではなく、むしろスケジューリング
のオーバーヘッドも加わって少し遅くなってしまうだろう。マルチコア全盛?
の昨今、早期のネイティブスレッド対応が望まれる。Java thread はたいてい
ネイティブスレッド対応なので jruby では案外簡単に実現できるのかも
知れない。Java の Thread クラスをラップすればいいだけだから。

Rails は相変わらず development mode でしか使用していないが、ファイルを
書き換えて、再アクセスするだけですむのはやはり便利で、スレッドを持たせ
てもこれでいけるか実験してみた。

Thread.new の戻り値を controller のスタティック変数に代入してみる。
スレッドのボディは単にスリープとカウンタの表示をするだけだ。コントローラ
を書き換え再アクセスすると新しいスレッドが作られるが、古いスレッドも
依然として動き続ける。定義は書き換えたのにだ! 短絡適にデストラクタや
スタティックデストラクタを思いついたが、いずれも Ruby のリファレンスには
見当たらない。クラスのアンロードのイベントやそれに伴ったハンドラの
呼び出しもざっとみたところでは見当たらない。スタティック変数は最ロード
された際に初期化されているので、あとから古いスレッドを触ることもできないようだ。

試行錯誤と妥協の後に、Thread.new の結果を外部クラスのスタティックフィールドに
保持し、新規スレッド生成時にという録されていたスレッドに Thread.exit する
事を思いつき、動作することを確認した。

小技の覚書

* 外部クラスの利用

Thread を覚えておいてあとでとめられるクラスを models の下に作ったが、
クラスが認識されずエラーになった。どこかでコントローラとモデルの関連
づけの記述があったような、なかったような... とりあえずは
require 'models/mythreadmanager' のようにして利用できるようになった。
あと、この require しているソース内にエラーがあった場合、rails の
エラー画面にはその詳細が出てこないようだ。このあたりは設定で表示
されるようにできるのかも知れないが、単体でデバッグして回避。

* Thread のイディオム


begin
@@threada = Thread.new do
# print "D: thread a2 starting...\n"
icnt = 0
while true
#print "thread a: " + Thread.current.to_s + " icnt " + icnt, "\n"
# printf "D: thread a2: %s icnt %d\n", Thread.current.to_s, icnt
sleep 10
icnt += 1
end
end

MyThreadManager.register @@threada
rescue
print "@@threada rescue\n"
p $!
end


基本的に begin/rescue の中で行う。そうしないと黙ってぬけられても
気付かない。

rescue は catch のように例外ごとに複数設けることもできるが、例外クラスを
定義しなければならない。$! は短いメッセージしか出さないように見えたので
例外そのものは取れないかと調べてみると rescue => evar とすることで
拾えることに気付くが、後に $! 自体が例外オブジェクトであり、$! を使って
スタックとレースも出せることに気付く。

* logger の使用

require 'logger' して次の2行程度で commons-logging みたいな機能が利用
できるようになる。


@@log = Logger.new STDOUT
@@log.level = Logger::WARN


* private 指定

どこかで private 指定は C++ のように private: 以下に書いたものと
漠然と覚えていたが、普通に定義して

private :checkLocalDir 

と private に続けてメソッド名のシンボルを書くことで private に
なるようだ。

* nil 地獄

クラスのフィールドが増えてくると to_s のオーバーライドの中や
ちょっとした if 文などで nil を参照したと言うことでエラーに
なる。少しうるさすぎる気がしないでもない。

* %r

正規表現に / が多く現れる場合、vi や perl などでは / を ! で
代用できる。これは ruby ではそのままでは動かないが
%r!/{1,}$! とする事で実現できる。

* unit test

require 'test/unit' して Test::Unit::TestCase のサブクラスを
作れば、テストクラスができる。テスト用のメソッドは test_ で
はじめる。setup の用途も JUnit と同じ。

* Queue

Queue クラスはスレッド間の連携に便利。何でも渡せそう。

* 外部コマンドの起動

外部コマンドを使わざる終えない状況で、以下にうまくそれをコントロール
できるかというのが問題になってくる。ポイントとしては子プロセスとの
標準入出力、エラーを用いた通信と終了ステータスの確認だ。

open("|sort", "r+") のようにすると返された IO に対して書き込み、読み込み
できる。本当に簡単な処理であればこれでいいが、エラー出力は得られないし、
コマンドのステータスも得られない。これにかんして Open3 モジュールを
使うと stdin, out, err ともに得られることがわかるが、Open3.popen3 は
内部で fork を使用している。これを使ってみてわかったが windows 版では
fork がサポートされていないため動かない。open("|comm...") はどうして
動くのかということになるが、調べる気が起きなかった。

結局、次のようにコマンドへの入出力はリダイレクトを使って戻り値は
system の戻り値をつかう方法が無難そうだし、windows でも動作した。


r = system('mysql -u test --password=test test <a.sql >out 2>err')

p r # true for success, false for error
p $? # additional info on failure

2007年5月30日水曜日

jhat, net/ftp, net/telnet

64-bit JVM の binary heap dump を見る必要が生じたので昔セットアップした
hat で見てみる。そうすると 64-bit はサポートしていない (4 byte の id
しかサポートしていない) といわれる。

適当に探すと jdk6 の jhat は 64-bit JVM のデータも見れるとの事。
確かに動いた。以前は興味もわかなかったが OQL という SQL みたいな
言語で heap dump にいろいろ検索をかけられる。複雑なクエリでは
クラスローダのリストを出したり System のプロパティをダンプしたりと
いうこともできるらしい。勉強してみよう。

---
ruby の ftp などは mechanize などを使わないといけないと早合点して
いたが、標準の Net パッケージに入っていることに気づいた。
jruby 上では ftp のリストや telnet の login 等がエラーになって
しまった。windows の ruby でやると エラーにならないことから、
jruby っぽい。bug をあげればいいのだろうか?

2007年5月28日月曜日

some experiments

企画中の Web Application の中に簡単にサーバー上のパスをたどれる
機能を持たせたい。まだ Struts を学び始めのころいろいろ試行錯誤
して断念したのを覚えていて、それからこれは億劫だ。

でも、Rails ならば手間が少ないだろうとはじめてみる。



  1. パス用の TextField の右に link を用意して、そのリンクが押されたら
    ディレクトリが選べるようにする。一旦ルートを離れると同様のアクションを
    引数つきで呼び出すファイルのリストも表示する。一旦構成要素が選ばれ
    たら TextField の内容も更新する。

    これは結構簡単にできて、よさそうだったが、テキストフィールドの
    初期値を処理に反映できない。わかっている部分までパスを入れて、
    その後の部分をアクションに補助してもらうということができない。
    なぜなら、link はフォームのフィールドを送れないからだ。たとえ
    text_field でドメインオブジェクトを TextField に結び付けて
    いてもだ。




  2. submit_tag でボタンを作ってそのアクションでディレクトリを選択して
    いく。この方法ではアクションをボタンの id で判別するしかないし、
    引数は渡せない。1と併用しなければならないし、そうするとコードが
    増えるだけだ。ボタン固有の引数が渡せると便利なのだが...


    もうひとつ、このような機能を持たせたいフィールド部分だけ、専用の
    フォームとして使用できないかと考えてみた。これにかんしては
    form tag のネストは標準的でないということで断念。




  3. 最後の方法は JavaScript の利用だ。できればこれは避けたかった。
    汎用的なものを作るのが難しいのと、デバッグがやりにくいというのが
    大きな理由だ。ただし、DOM と非同期通信を使えばいろいろなことが
    できるはずだ。


    Spring 2.0 本でみた DWR のサンプルを思い出した。ぱっと見は現在の
    ウインドウの中にモーダルウィンドウが現れて、そこに操作をして
    submit という流れに見える。



    サンプルを見ていくと script.aculo.us の effect の Effect.Appear
    を使って小さなウィンドウを表示しているように見える。その機能だけを
    試してみると画面上の div 要素を効果をつけて表示している。どう見ても
    モーダルウィンドウを表示するとはことなる動きだ。



    ちょっと考えて、確認して納得したが、サンプルでは CSS を使って
    位置、サイズを固定した div 要素に対して Effect.Appear を使っている。
    サンプルとしてはいいのだが、これでは困ったことがおきるのではないか?
    画面上に他の画面に移行するフォームやリンクがあったらどうする?



    script.aculo.us を検索していると lightbox というライブラリを見つけた。

    http://www.huddletogether.com/projects/lightbox2/

    サンプルで写真を選ぶと (CSS で作ったと思われる) ウィンドウが現れ
    拡大された写真が表示される。背景にはシェーディングがかかって
    暗くなっている。見た目はなかなかいいぞ。




元はといえば WLS の deploy 画面が便利だなという漠然とした感想が
あったのだが、よく考えるとこちらはフォームを使っていない。
何らかの基点を記憶させて置くことはできるのかも知れないが、
これくらいなら作れそう。

http://localhost:7001/console/console.portal?
_nfpb=true&
_pageLabel=AppApplicationInstallPage&
AppApplicationInstallPortletISUNIX=YES&
AppApplicationInstallPortletFILECHOOSERPATH=%2Fhome%2Froot


----
関連情報を探しているうちに ajax4jsf というのを見つけた。
サンプルの war が見当たらない...

https://ajax4jsf.dev.java.net/
http://jboss.org/projects/jbossAjax4jsf

2007年5月20日日曜日

Ruby on Rails notes

Rails に関するページや本をざっとみてこれはデータベース依存の大きな
フレームワークで、色々な制約があって単純に Web Application を移植
する対象として見れないのではないかという印象を受けていたが、よく
見て行くと、そうでもないらしい。

単純なケースとして rails で作成したプロジェクトにひとつコントローラを
設けるだけでページとして機能する。

> rails simple
> cd simple
> ruby script\generate controller info
> notepad app\views\index.rhtml

これだけでよい。以前、色々試したときの経験から自動生成されている
config\database.yml の設定が邪魔をするかとも心配したが、モデルが
何もなければデータベース接続は発生しない。

次のステップとしてリンクやフォームの処理が気になってくる。

コントローラの中には次の様な記述がよく現れる。
render :action => 'new'

ruby では推測可能な部分の括弧は書かなくてもよいという特徴がある。
なんとなくハッシュを渡しているのはわかるが、なぜキーがシンボル
(:name :に続けて識別子のようなもの)なのか今ひとつ不明。
http://www.rubyonrails.org/ から API のページを見てみる。
http://api.rubyonrails.org/ 色々と説明はあるのだが今ひとつ
仕組みがぴんとこない。

http://www.rubyonrails.org/ に Source のリンクがある。
そこに SVN の URL がある。ブラウザで開いてみるとソースをブラウズ
出来た。
http://svn.rubyonrails.org/rails/branches/1-2-stable

API の各ページのはじめに定義があるファイル名が表示されている。
そのパスを参考に実際のソースを見ることが出来る。

render の場合は次のパス。
http://svn.rubyonrails.org/rails/branches/1-2-stable/actionpack/lib/action_view/base.rb

link_to の場合は次のパスになる。
http://svn.rubyonrails.org/rails/branches/1-2-stable/actionpack/lib/action_view/helpers/url_helper.rb

これらのソースに symbolize_keys というメソッドがハッシュに対して
よばれているところがある。ハッシュに関するメソッドかと思い、小さな
スクリプトで動作を確認しようとすると、そんなメソッドはないといわれて
しまう。

Rails の API を見ると vendor/rails/activesupport/lib/active_support/core_ext/hash/keys.rb
の中で定義されている。パスの名前から (core_ext) rails の activesupport
でハッシュの機能を拡張していることのように見える。

activesupport を require して試してみようとも思ったが rails の
コントローラで試しても同じことだろうと思ってコントローラの中で
ハッシュに対して symbolize_keys をハッシュに対して呼んでみる。

その結果 "abc" => "ABC" が :abc => "ABC" のように変わって
入ることがわかった。これからいくと render/link_to の引数で

render :action => 'new'

と書くのは

render 'action' => 'new'

と同じということだろう。ではなぜか?

おそらく、文字列のためのメモリをセーブするためではないか。
Java でいうところの String.intern() にあたるのではないかと
おもう。

----------
では上記の render 文が何をするかということだが、action で
指定された view をクライアントに返すということのようだ。
極端な場合、コントローラーアクションは色々定義しても
ひとつの view (rhtml file) で表示させることも出来る。

コントローラを作ると ApplicationController のサブクラスが
作られるがこの中にアクションに対応したメソッドを定義して
おくことで呼び出すことが出来る。


def list
@item_pages, @items = paginate :items, :per_page => 10
end


この後、アクションと同じ名前 + .rhtml で表示が行われる。

index.rhtml に関しては index というアクションがなくても
良いようだ。また、'index' というアクションで index ページ
を表示させることもできる。

----------
.rhtml (embedded ruby) の側ではリンクに次の様なものが現れる。

<%= link_to 'Show', :action => 'show', :id => item %>
<%= link_to 'Previous page', { :page => @item_pages.current.previous } if @item_pages.current.previous %>

link_to も Rails のメソッドで API doc を見て行くと仕様がわかる。

link_to(name, options = {}, html_options = nil, *parameters_for_method_reference)

最初のケースでは :id => item という引数を渡しているがここには任意の
物が指定できるようだ。ただし、受けたコントローラでは symbolize_keys
の逆操作が行われているようで、key を :myparam としてもコントローラで
params をダンプしてみるとキーは "myparam" となっている。ただし、
依然として params[:myparam] での参照は可能。

また、item は item.id と同意ということのようだが、これがどこからきている
かは今のところはっきりしない。

----------
http://railsapi.masuidrive.jp
AJAX を使用した部分的に日本語化された rails のマニュアル。

----------

def list
@item_pages, @items = paginate :items, :per_page => 10
end


これはレコード数が多くなる可能性のあるページに使うイディオムの
様だが左辺が二つある。よく考えると多重代入だし pagenate の API
にも pagenator と collection を返すと書いてある。

複数の値を返すという概念は C++/Java にはないので少し困惑したが、
多重代入の本質はリストを返すことと、それをどのように代入、グルーピング
するかということで、メソッドの最後でリストを評価すればいいと言う
事。便利だが、仕様をしっかり書いておく必要がある。

----------
フォーム


<% form_tag :action => 'escape' do %>
<%= text_area 'etext', 'rawtext', :rows => 8 %><br/>
<%= submit_tag "Escape" %>
<% end %>


Form は form_tag を使って作ることが出来る。:action にポストを
受けるアクションの名前を指定する。
text_area の引数に迷ってしまったが、適当でもポストはできた。
ただ、同じ view でうけると表示上のデータは消えてしまう。
要は部品にバインドできていない状態だ。

これは最初の引数をコントローラのフィールドのドメインオブジェクトの
名前に、二番目をそのフィールドにすることで解決できたようだ。
上記の例では


def escape
@etext = Etext.new
@etext.rawtext = params[:etext][:rawtext]
@etext.escape
render :action => "index"
end


Etext は app/models/etext.rb で次のように定義している


class Etext
attr_accessor :rawtext
attr_accessor :escaped_text
def escape
@escaped_text = @rawtext.gsub(/&/, '&amp;').
gsub(/</, '&lt;').gsub(/>/, '&gt;');
end
end


生成される HTML は次のようになる。


<form action="/info/escape" method="post">
<textarea cols="40" id="etext_rawtext"
name="etext[rawtext]"
rows="8">...</textarea><br/>
<input name="commit" type="submit"
value="Escape" />
</form>


ポストされたデータは params という名前のハッシュで参照できて
次のようになっている。

{"commit"=>"Escape", "action"=>"escape",
"controller"=>"info", "etext"=>{"rawtext"=>"..."}}
----------
||=

これは変数が nil の場合のみ右辺値を左辺値に代入するというオペレータ

----------
variable.nil?

これは変数が nil かどうかをテストするメソッド。未定義、未設定のものに
テストできるのは面白い。C++/Java でやれば例外、エラーになるところだ。

----------
@rawtext.gsub(/&/, '&')

gsub() は指定された置き換えの結果を返すが gsub!(...) では元の
文字列が書き換えられる。! は破壊的動作のしるし。C++ でいうところの
非 const 関数といったところか。? は問い合わせ
をするようなメソッド名の最後につけておくという慣例らしい。

----------
クラス名は大文字で始める必要がある。

フィールドの定義は attr_accessor でできる。引数はフィールド名の
前に : を付けた物(シンボル)

attr_accessor :rawtext
attr_accessor :escaped_text

----------
Model の定義に関係を belongs_to などで指定できる。


class ListItem <ActiveRecord::Base
belongs_to :user
end


一見、設定ファイルに関係性を明示しているようにも見えるが(案外、それが
目的の設計かも知れないが) これは Ruby のクラス定義である。では
belongs_to は一体何なのか。これも API をたどって行ってわかったが、
これは ActiveRecord::Base のクラスメソッドである。クラスメソッドが
このようなところに書いてあると何が起こるかというとクラスがロード
されるときにこのクラスメソッドが実行される。なるほどね~。

----------
Windows 上のファイル編集には Terapad と cygwin 内の vim を使っていた。
たまたまフリーの EmEditor をいうのを見つけたので使ってみると Terapad
の Tab 版といった感じでなかなかよさそう。デスクトップがごちゃごちゃに
ならないところがいい。

----------
view の中では controller のインスタンス変数を文法上そのままアクセス
できるが、これはリフレクションのような手法を使って巧みに作り込まれた
物らしい。controller オブジェクトだが、シングルトンではないらしい。
あるアクションで設定したインスタンスフィールドを別なアクションで
表示してみると nil になっていた。

----------
最初は暗号のように見えたコントローラや rhtml の記述もその意味がわかって
くるとなかなか味がある。Ruby は以前、挑戦したのだが、その時点では
将来性が良くわからず直ぐに忘れてしまった。数年を経て C++ やら Java を
(自分としては)深く使い込んだ今見直してみると中々興味深い言語だ。
Rails はその機能をうまく拡張、利用しているようだ。

native library 依存がない物であればほぼ jruby で動くというところも
すばらしい。ruby - bytecode 変換が早く実現されないかとたのしみでもある。

2007年5月16日水曜日

Ruby on Rails First Impression

JavaOne の Ruby on Rails のデモ -- サンプルを war にして app server に
配置してみたり、動的更新をしてみたり -- がどうも気にかかっていたので、
以前やりかけてやめていた Ruby on Rails から挑戦。

手近に Linux がないので Windows で試す。日本語の短いデモにしたがって
ActiveScriptRuby で出てくるサイトからダウンロード、インストール。
gem は最初から使えるようで、remote で rails をインストール。

MySQL Manager もあるらしいことは知っていたがずっとコマンドラインだった。
でも使いやすそうなのでインストール。

あとはデモどおりに作っていくとその通りに動く。上記の短い日本語のデモは
単純すぎていまひとつだったが、環境構築に役立った。本家のデモを見ていく
事で view のいじり方の雰囲気がわかった。

同じ事をプロキシの中でやろうとしてみた。gem には --http-proxy オプションが
あるのだがこれがなかなか動かない。gem は gem ファイルからもインストール
できるので rails の gem ファイルをダウンロードしてきてインストールしようと
するが、結構依存するモジュールがあり、エラーを食らってはダウンロード、
インストールを繰り返し、何とか動くところまで持っていけた。

次に Unix 上での動作確認をしたいのだが、対象 OS が OSS に弱くてディスクも
あまりないので、あきらめようとしていたが、JRuby、そして JRuby on Rails も
結構動くらしいことを知る。

適当な JRuby をダウンロード、セットアップすれば、JDK があれば動いてくれる。
そのあとは gem 操作はほぼ同じ。ただし、多くのコマンドは

jruby $JRUBY_HOME/bin/gem ... のように jruby でコマンドラインをはじめる
必要があるようだ。ファイルを一つ一つインストールしたときの gem ファイルが
役に立った。

いろいろなところで書かれてはいたが、Rails はデータドリブンなので
どうしてもデータベースを用意しなければいけないらしい。Controller と
View だけでいろいろ試して見ることができたら便利そうだろうと model
の作成を飛ばしてやってみたが、generate scaffold の中でアクセスに
いってしまう。

そういうものだと割り切ってリモートの MySQL のデータベースを指定。
scaffold もできた。

$ jruby script/generate controller abc
exists app/controllers/
exists app/helpers/
create app/views/abc
exists test/functional/
create app/controllers/abc_controller.rb
create test/functional/abc_controller_test.rb
create app/helpers/abc_helper.rb

$ jruby script/generate scaffold abc
exists app/controllers/
exists app/helpers/
create app/views/abcs
exists app/views/layouts/
exists test/functional/
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/abc.rb
create test/unit/abc_test.rb
create test/fixtures/abcs.yml
#28000Access denied for user 'root'@'localhost' (using password: NO)


$ jruby script/generate scaffold abc
exists app/controllers/
exists app/helpers/
exists app/views/abcs
exists app/views/layouts/
exists test/functional/
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
identical app/models/abc.rb
identical test/unit/abc_test.rb
identical test/fixtures/abcs.yml
/usr/local/jruby-0.9.2/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/vendor/mysql.rb:155 warning: JRuby does not currently support defining finalizers
create app/views/abcs/_form.rhtml
create app/views/abcs/list.rhtml
create app/views/abcs/show.rhtml
create app/views/abcs/new.rhtml
create app/views/abcs/edit.rhtml
create app/controllers/abcs_controller.rb
create test/functional/abcs_controller_test.rb
create app/helpers/abcs_helper.rb
create app/views/layouts/abcs.rhtml
create public/stylesheets/scaffold.css

---------

rhtml はほとんど JSP の感覚で触れる。リンク周りの書き方が少しわかりづらいが
テーブルの背景色を互い違いにするといったことぐらいであればうろ覚えの
Ruby コードをスクリプトレットのように使って簡単に実現できてしまった。

<table>
<tr>
<% for column in Abc.content_columns %>
<th><%= column.human_name %></th>
<% end %>
</tr>

<% idx=0; %>
<% for abc in @abcs %>
<% if (idx%2)==0; bgcolor="#ffffff"; else ; bgcolor="#cccccc"; end %>
<tr bgcolor=<%= bgcolor %> >
<% for column in Abc.content_columns %>
<td><%=h abc.send(column.name) %></td>
<% end %>
<td><%= link_to 'Show', :action => 'show', :id => abc %></td>
<td><%= link_to 'Edit', :action => 'edit', :id => abc %></td>
<td><%= link_to 'Destroy', { :action => 'destroy', :id => abc }, :confirm => 'Are you
sure?', :method => :post %></td>
</tr>

<% idx = idx + 1 %>
<% end %>
</table>

<%= link_to 'Previous page', { :page => @abc_pages.current.previous } if @abc_pages.curren
t.previous %>
<%= link_to 'Next page', { :page => @abc_pages.current.next } if @abc_pages.current.next %
>

一旦 rhtml を生成した後でテーブルに変更を加えると list 操作には
すぐ反映されるが new, edit には反映されない。これらは _form.rhtml
をインクルードしていて、それ自身はデータベースの構造変更に
追従するわけではない。ここで generate scaffold すると存在する
ファイルに関しては上書きするかどうか聞いてきてくれる。_form.rhtml は
今のところ触っていなかったので、この方法で更新。

$ jruby script/generate scaffold abc
exists app/controllers/
exists app/helpers/
exists app/views/abcs
exists app/views/layouts/
exists test/functional/
dependency model
exists app/models/
exists test/unit/
exists test/fixtures/
identical app/models/abc.rb
identical test/unit/abc_test.rb
identical test/fixtures/abcs.yml
/usr/local/jruby-0.9.2/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/vendor/mysql.rb:155 warning: JRuby does not currently support defining finalizers
overwrite app/views/abcs/_form.rhtml? [Ynaqd] Y
force app/views/abcs/_form.rhtml
overwrite app/views/abcs/list.rhtml? [Ynaqd] n
skip app/views/abcs/list.rhtml
identical app/views/abcs/show.rhtml
identical app/views/abcs/new.rhtml
overwrite app/views/abcs/edit.rhtml? [Ynaqd] n
skip app/views/abcs/edit.rhtml
identical app/controllers/abcs_controller.rb
identical test/functional/abcs_controller_test.rb
identical app/helpers/abcs_helper.rb
identical app/views/layouts/abcs.rhtml
identical public/stylesheets/scaffold.css

このように JRuby on Rails は簡単に動いてしまったが、それを
war ファイルに変換する方法がすぐにわからないので検索してみると
Rails に似た Trails というのがあるらしい。こちらは最初から
java 用で model は java でコーディングする必要があるようだ。
今回は時間切れなので Trails はまたの機会にする。

古い JBoss や Tomcat をはじめて触ってはまりまくったときに比べると
すんなりと動作まで持っていけた。確かに柔軟性にかけそうな部分は
あるし、細かな書き方がいまひとつわからないがあっさりと動いて
くれるともっともっと触りたくなる。こうやって信者になってくのか???

うろ覚えで書いてみたものが動いた。文法は Perl ほどではないが、
どうも好きになれない...

def mathop(n)
rv = 0
i = 0
while i <= n
rv += i
i=i+1
end
return rv
end

printf "result %d\n", mathop(100)

2007年5月9日水曜日

Axis2, Spring Web Services, JavaOne 2007 Opening

XML-RPC に使える OSS として Axis を調べていたけど、どうやら Axis2 に
置き換えられている。Spring Web Services もオフィシャルリリースまで
もう一歩というところ。

---
JavaOne 2007 General Session から
昨年もそうだったが始まる前のステージがかっこいい。
Joe Green も板についてきた。マクネリも半袖のジョブスがうちにもきて
良かったと冗談を言っていた。

何に含まれているのか聞き取れなかったがリアルタイム java platform には
javax.realtime.RealtimeThread というスレッドがある。Solaris はリアルタイム
版の java 環境をサポートするための機能をもつ。この環境での GC が
どういうものなのか気になる。

ERICSSON GlassFish ベースのモジュールをオープンソースとして寄贈する

NASDAQ の取引は java プラットホーム上で行われており日に 50億トランザクションに
上るときもある。2007/02/27 の大量発注も裁ききった。

SONY: BlueRay が順調で何より

NetBeans 6.0: 新しい editor やサポート言語の拡張など

openJDK のオープン化が完了。最近見ていなかったが、クラスライブラリも
open になったのか? TCK というテストキットもオープンになった。
(Apache から test kit がオープンでなかったので Harmony VM が最初の
open JVM になれなかったと苦情があった...)

GPLv2 を利用。

Faster, faster, faster -- Java SE 6.0 に起動、動作にかかわるパフォーマンス
向上を次々にリリースしていく。

JavaFX:
Java SE 上で動くスクリプト環境で、リッチな GUI, Web 等が作れる。
Flash or PS シリーズの GUI 見たいな感じのものをデモしていた。

JavaFX Mobile:
Mobile にも SE 環境を提供し、その上で動く FX も提供していく。

Yahoo GO : Java FX Mobile を使い、リッチなポータル、サーチ画面を提供していく。

インターネットにつながるデバイスの総数で考えると携帯は PC の 20 倍である。
18 億のモバイル Java user がいる。この部分にてこ入れしていく。

教育や、環境にも貢献していきたい...

2007年5月7日月曜日

iBATIS JPetStore-5.0 sample

修正なし、DB セットアップなしで動いてくれるところがうれしい。Tomcat, Jetty で
問題なく動作した。

以前少しだけ触った winstone だが、JSP のタグがそのまま表示されていて
機能が限られていると思っていたが、使い方がまずかった。Winstone 自体には
JSP のランタイム、コンパイラがないのだ。

Tomcat から ./lib または --commonLibFolder=... で指定したディレクトリに
jasper 関連、commons-logging.jar をコピーして --useJasper=true を
つけて起動するとちゃんと動いた。

java -jar ../winstone-0.9.6.jar --httpPort=8989 \
--ajp13Port=8988 --useJasper=true \
--warfile=../ibatis_sample/JPetStore-5.0/build/wars/jpetstore.war

iBATIS で BMP を実装しているケースを少し確認しないといけないので
サンプルを読み解いていく必要がある。

ゼロから作ってもいいのだが、設定ファイルの配置に関する決まりごとなど
あるとはまりそうなのでサンプルからはいるのがよさそう。

あと Abator という Eclipse plugin で設定ファイルが簡単に作れるようだが、
私は NetBeans 派。NetBeans/Eclipse を同時にあげるメモリもない...

---
Spring のサブプロジェクトに rich client とか web service といった
面白そうなものを発見。今度試してみよう。

Transaction

Spring framework の TransactionManager を使用してみる。
(この部分に関しては初めてなので、内容は実験的なもので
実践的なものではありません。)

Hibernate で大量のデータを insert していくと非常に時間がかかる。
メモリ内に持つ場合に比べてオーダが2つか3つ異なる。出し方は
忘れたが、auto-commit モードでは遅いよ見たいな事を言われたことが
あったので、設定ファイルでプロパティとしてオフにしてみたり
SQLConnection/Statement を得てオフにしてみたりしたが効果がない。

ではいったいどうやって auto-commit をオフにするかを考えていた。
もちろん、全てを素の JDBC でやる気は毛頭ない。ぼんやりと思って
いたのは Spring の TransactionManager を使えばオフになるのでは
ということ。

1.X の文法はなんともわかりにくかった。2.0 の aop/tx の形式なら
何とかなるかもということでやってみる。


<aop:config>
<aop:advisor pointcut="execution(* *..XRecDaoImplTx.insertXRecord(..))"
advice-ref="txAdvice"/>
</aop:config>

<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="insertXRecord"
propagation="REQUIRED"
timeout="20"/>
</tx:attributes>
</tx:advice>


ところがこれだけではどうも効果がわからない。
aop, transaction のログレベルを DEBUG にすると動作がなんとなく
わかるようになる。


log4j.category.org.springframework.transaction=DEBUG
log4j.category.org.springframework.aop.config=DEBUG



[main] DEBUG (NameMatchTransactionAttributeSource.java:addTransactionalMethod) - Adding transactional method [insertXRecord] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_20]
[main] DEBUG (NameMatchTransactionAttributeSource.java:addTransactionalMethod) - Adding transactional method [xrec1Tx] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_20]
[main] DEBUG (TransactionSynchronizationManager.java:bindResource) - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@146c2f2] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] to thread [main]
[main] DEBUG (TransactionSynchronizationManager.java:initSynchronization) - Initializing transaction synchronization
[main] DEBUG (TransactionAspectSupport.java:prepareTransactionInfo) - Getting transaction for [ibatisinteg.dao.XRecDao.insertXRecord]
[main] DEBUG (TransactionSynchronizationManager.java:getResource) - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@146c2f2] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] bound to thread [main]
[main] DEBUG (TransactionSynchronizationManager.java:getResource) - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@146c2f2] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] bound to thread [main]
[main] DEBUG (TransactionAspectSupport.java:commitTransactionAfterReturning) - Completing transaction for [ibatisinteg.dao.XRecDao.insertXRecord]
[main] DEBUG (TransactionSynchronizationManager.java:clearSynchronization) - Clearing transaction synchronization
[main] DEBUG (TransactionSynchronizationManager.java:unbindResource) - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@146c2f2] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] from thread [main]
[main] DEBUG (TransactionSynchronizationManager.java:bindResource) - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@178bb14] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] to thread [main]
[main] DEBUG (TransactionSynchronizationManager.java:initSynchronization) - Initializing transaction synchronization
[main] DEBUG (TransactionAspectSupport.java:prepareTransactionInfo) - Getting transaction for [ibatisinteg.dao.XRecDao.insertXRecord]
[main] DEBUG (TransactionSynchronizationManager.java:getResource) - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@178bb14] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] bound to thread [main]
[main] DEBUG (TransactionSynchronizationManager.java:getResource) - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@178bb14] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] bound to thread [main]
[main] DEBUG (TransactionAspectSupport.java:commitTransactionAfterReturning) - Completing transaction for [ibatisinteg.dao.XRecDao.insertXRecord]
[main] DEBUG (TransactionSynchronizationManager.java:clearSynchronization) - Clearing transaction synchronization
[main] DEBUG (TransactionSynchronizationManager.java:unbindResource) - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@178bb14] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1d9a2ab] from thread [main]


よく見ると Getting Transaction for [method name] と Completing transaction for [method name]
が繰り返し出てきている。実際に数えると insert と同じ回数出てきている。

これから、ポイントカットに入るときに開始して、出るときに終了しているらしいことが
わかる。これでは元のつくりより遅いではないか。

では大量の insert を行う処理を呼ぶ側につけてはどうか。

これをやっているときにも少しつまづいた。ポイントカットに指定するメソッドは
インターフェイスで定義されたものの実装でなければならないようである。
当然、static メソッドは使えない。継承関係が複雑な場合(あるインターフェイスを
実装した抽象クラスのサブクラスが他のインターフェイスを実装していてといった
感じ) でもうまく動かなかった。

試行錯誤の後、この方法でトランザクション中はコミットが入らずデータの追加が
早くできた。失敗した場合のことはまだ考えていない。エラーが起きないように
データを用意するか、それともエラーが起きたときにデータをチェックして正しい
データのみ登録するか、それぞれ面倒そうなのでじっくり考えることにしよう。

最初に設定したデータベース処理に近いポイントカットも enable してみると
パフォーマンスの低下は見られなかった。どうやらネストしたトランザクション
スコープからぬける際はフラッシュはかからないようだ。

ibatis のバッチモードも大量データ追加に効果があるようなことが書かれていたので
試してみたが、いまひとつ。むしろ TransactionManager が効果的のようだ。
(試したサンプルは batch mode を transaction 開始、終了で囲んであったので
batch だけやっても意味はないのかも)

Hibernate のパフォーマンスだが、最終的にはトランザクションを使わない場合の
2, 3 倍程度となった。(Embedded Derby の場合) これは少し期待はずれ。
MySQL でやると改善率は高いのだが、もともとがとても遅いわけでやはりこれも
使えない。

Hibernate をつかったプログラムでは自前でバッチ更新するコードを入れていた
(Hibernate template に Collection をわたす)。この場合、ひとつのセッションの
中で更新・追加が行われるわけで TransactionManager を使わなくとも早く
できることがわかった。ただ、エラーハンドリングをどうするかは依然として
課題である。ibatis のバッチモードもこのようなことなのかも知れない。

かなり入り口の部分でポイントカットを設定して走らせて見ると OutOfMemoryError が
でた。commit するまではどこかにためておかれるみたい。定期的にフラッシュする
簡単な方法があると良いのだが。トランザクションの本来の使い方から大きく
逸脱しているので難しそうだが...

結局、大量のデータ登録を行うには DB 固有の import がもっとも速そう。しかし、
これもいろいろな制約のついたテーブル構造・関係の下ではいろいろなエラーが
おきうるので頭が痛い...

2007年5月3日木曜日

XML catalog

SqlMap の設定を NetBeans で作っていると、補完機能が効かないのに気づいた。

以前作った spring 用の XML catalog ファイルを参考に catalog ファイルを作成してみる。
あっさりと動いた。このケースでは DTD のエントリしかないが、XML Schema でも同じ。

<?xml version="1.0"?>
PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<system systemId="http://www.ibatis.com/dtd/sql-map-config-2.dtd"
uri="sql-map-config-2.dtd" />
<system systemId="http://www.ibatis.com/dtd/sql-map-2.dtd"
uri="sql-map-2.dtd" />
</catalog>


こちらが spring 用に作ったもの。

<?xml version="1.0"?>
PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<system systemId="http://www.springframework.org/dtd/spring-beans.dtd"
uri="spring-beans.dtd" />
<system systemId="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
uri="spring-beans-2.0.xsd" />
<system systemId="http://www.springframework.org/schema/util/spring-util-2.0.xsd"
uri="spring-util-2.0.xsd" />
<system systemId="http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
uri="spring-aop-2.0.xsd" />
</catalog>


ファイルは DTD, Schema のあるディレクトリに .xcat の拡張子で保存した。
NetBeans の Runtime tab / DTD and XML Schema Catalogs を右クリック, Add Catalogs
で追加できる。

2007年5月1日火曜日

HTML escape

このサイトでは <, > のエスケープが効いていないみたい。プログラムや、XML の
ソースを引用するには少し不便。以前作った PHP 版の簡易エスケープツールを
SpringMVC で作り直してみた。とりあえず動作確認。



<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

<!-- Acegi config -->

<bean id="authenticationManager"
class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider"/>
</list>
</property>
</bean>

<bean id="daoAuthenticationProvider"
class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>

<bean id="userDetailsService"
class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userProperties">
<props>
<prop key="admin">pass,ROLE_USER,ROLE_ADMIN</prop>
<prop key="guest">pass,ROLE_USER</prop>
</props>
</property>
</bean>

<bean id="accessDecisionManager"
class="org.acegisecurity.vote.AffirmativeBased">
<property name="decisionVoters">
<bean class="org.acegisecurity.vote.RoleVoter"/>
</property>
</bean>

<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/process-login"/>
<property name="defaultTargetUrl" value="/index.jsp"/>
<property name="authenticationFailureUrl" value="/error/error-login.html"/>
</bean>

<bean id="logoutFilter"
class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/"/>
<constructor-arg>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</constructor-arg>
<property name="filterProcessesUrl" value="/process-logout"/>
</bean>

<bean id="sessionIntegrationFilter"
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
</bean>

<bean id="anonymousProcessingFilter"
class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
<property name="userAttribute" value="anonymous,ROLE_ANONYMOUS"/>
<property name="key" value="anonymousKey"/>
</bean>

<bean id="filterSecurityInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/login.html=ROLE_ANONYMOUS,ROLE_USER
/process-login=ROLE_ANONYMOUS,ROLE_USER
/user-info.jsp=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/error/**=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/css/**=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/index.jsp=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/welcome.html=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/vmstat.html=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/*.js=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/dynimg/**=ROLE_ANONYMOUS,ROLE_USER,ROLE_ADMIN
/admin/**=ROLE_ADMIN
/**=ROLE_USER,ROLE_ADMIN
</value>
</property>
</bean>

<bean id="exceptionTranslationFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.html"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/error/error-access.html"/>
</bean>
</property>
</bean>

<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=sessionIntegrationFilter,logoutFilter,authenticationProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor
</value>
</property>
</bean>
<!-- end Acegi config -->

<bean id="customerService" class="uxtool.webflow.DefaultCustomerService"></bean>

</beans>

2007年4月30日月曜日

Axis, XML RPC, JAX-RPC などなど

もやもやっとしてた Axis を少し勉強。

最近の更新履歴を見る限りあまり活発な状態には見えない。

バイナリディストリビューションを展開すると webapps の下に axis という
ディレクトリがあって webapp の形をしている。これをディレクトリごと
サーブレットコンテナの webappsにコピーする。設定ファイルを更新
したりする必要があるので WAR にまとめてはいけない。

何が出来るかというとコンテナに配置した Axis サーバにユーザが
作ったサービスを登録して呼び出すことが出来る。

形式には AdminService を使って wsdd ファイルを与えて一連の
クラスを登録する方法と java program のソースを .jws 拡張子で
webapps/axis に置き、サーバにコンパイル、配備させる方法の
二つがある。後者はパッケージや、複雑な指定が出来ないため、
凝ったことは出来ない。

WSDL というサービスを記述した情報がクライアントアクセスに必要に
なるが、これは手で書くわけではなく、.wsdd を元に動的に生成されて
いるらしい。サービスの URL に?wsdl をつけてブラウザでアクセス
すると表示される。

Axis/SOAP の位置づけを考えれば当然なことなのだが、扱える
データ型に色々と制約がある。XML でマーシャリングするという
ことは、XML スキーマで記述できるデータでなければならない
ということであり、標準定義されているのはプリミティブ型、文字列、
日付程度である。wsdd に型に関する情報を記述すれば比較的
シンプルな JavaBeansは扱えるが、込み入ったオブジェクト群を
送るのは面倒なことに思える。コレクションも送れない。RMI では
ないのだ。wsdd を熟知するかその記述を自動化する方法が
ないうちはプリミティブデータの配列程度に収めておくのが無難
そうだ。文字列でやり取りをして必要に応じてそれをパースする
ほうがシンプルでよいのかも。でもそう考えるとせっかくデータ
記述性に優れた XML を使ってる意味がよくわからなくなる。
Bean の配列程度でもある程度の表現は出来ないことはない。
逆に考えると Java オブジェクトを渡すということは双方で同じクラス
定義を使用しないといけないことになる。ざっと見た感じでは
RMI では可能なクラスの共有方法などがない。

少しがっかりしたが、関連技術を調べてみるとそうでもないらしい。
ここでは XML RPC の詳細を述べていないが、まずサンプル
として最初に動かす物や JWS は privider="java:RPC"
(or style="RPC")になっている。プロバイダが java:RPC で
あれば Axis ランタイムがシリアライズ、デシリアライズを行う。
その際に XML Schema での記述力、標準で用意された
データタイプに縛られるということである。

スタイルには java RPC のほかに Document, Wrapped, Message
がある。斜め読みだが、Document スタイルを使うとユーザーが
データのシリアライズ。デシリアライズを記述できるように書いて
あるページもある。Axis のドキュメントを見る限りは XML として
サーバー側でデータを受けるときにつかうスタイルは Message
スタイルなので Document ではないのではないかと思ったりもしたが、
Message スタイルで定義できるメソッドのシグネチャに次の
物があり、"Document で..." という記述はこのシグネチャの中の
(DOMだっけ?) のXML 記述型としての Document のことを
言っていたのだと思う。

public Document method(Document body);

スタイルとしての Document, Wrapped は今ひとつ有用性がわからない。

関連する規格に関しても確認してみた。まだ、大雑把で、バージョン
ごとの違いもとてもあいまいなのだが...

JAX-RPC
XML RPC の規格。Java 1.4 でも動作するが機能は少なそう。

JAX-WS
JAX-RPC の後継のようだが Java 1.5 の機能に依存している。

JAXB
Java と XML データのバインディングの規格。

Java オブジェクトのやり取りという点では Axis に Message スタイルの
サービスを用意して JAXB でデータのシリアライズ、デシリアライズを
するようにすると RMI に近い感覚で使えそう。

調べてみると面倒そうなところが見えてきて少し億劫になってしまいそうだ。
----
今日のレッスンは少し少なめ。スタイルもオーソドックスに逆戻り。
でも、それがいいかも。
今期はこんなところで次に期待。方向転換をいれてくれると面白いけど。