Java SE API を JRuby から利用する方法はいろいろな所で紹介されている。
変に load_class してしまうことで素性が Java なのか Ruby なのか
わかりにくくなってしまうのは好きではないのでフルパッケージ名で
使用していた。
いざ自分の定義したクラスを使おうとしてみるとうまくいかない。
試行錯誤の結果必要なのは CLASSPATH を適切に設定して load_class
でクラスをロードすることが必要らしい。たとえロードしてもフルパッケージ名
では参照できない。
2007年6月21日木曜日
2007年6月11日月曜日
SimpleFormController
Form を使ったページを作成しようとして昔のソースを見て困った。
ど忘れしている、というかよく覚えていない。
command って何だっけ?
答えは config ファイルで設定していた。
次のメソッドもオーバーライドしているがなぜやっているのか思い出せない。
答えは AbstractFormController の API ref にあった。onSubmit() は bind,
validate にエラーがなかった場合にのみ呼ばれる。そのため、エラーにかかわらず
リクエストプロパティをビューに渡したいときなどに formBackingObject()
でセットしてやるとよい。忘れずに super.formBackingObject() を呼ぶこと。
納得して POJO を作ってみる。int フィールドがいるのだが、validation
は自前でする必要があるのだろうか...
validator は Validator を implement して inject してやればよい。
validator, controller は Errors の参照が渡される場所ではこれに
reject* する事でエラーを登録する。
ど忘れしている、というかよく覚えていない。
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 にはすこし具体的なエラーが出ているのでこういう時は
こちらからあたりをつけていくしかない。
いろんなエラーで戸惑ってしまう。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/rescue の中で行う。そうしないと黙ってぬけられても
気付かない。
rescue は catch のように例外ごとに複数設けることもできるが、例外クラスを
定義しなければならない。$! は短いメッセージしか出さないように見えたので
例外そのものは取れないかと調べてみると rescue => evar とすることで
拾えることに気付くが、後に $! 自体が例外オブジェクトであり、$! を使って
スタックとレースも出せることに気付く。
* logger の使用
require 'logger' して次の2行程度で commons-logging みたいな機能が利用
できるようになる。
* 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 でも動作した。
時間がきたら何かを始めるような、例えばリモートのファイルの更新を調べて
更新があればその変更をローカルに反映させる、といったことがやりたい。
後に 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
登録:
投稿 (Atom)