カスタム検索

2009年12月26日土曜日

Lift On!

Scalaに引き続きLiftのテスト

・Mavenが入っていると簡単

mvn archetype:generate -U -DarchetypeGroupId=net.liftweb -DarchetypeArtifactId=lift-archetype-basic -DarchetypeVersion=1.0 -DremoteRepositories=http://Scala-tools.org/repo-releases -DgroupId=demo.helloworld -DartifactId=helloworld -Dversion=1.0

で雛形からなにやらダウンロードしてくれる

・helloworld というフォルダがプロジェクトになっているので、ここへ移動して jetty で起動する

cd helloworld
mvn jetty:run

で、 http://localhost:8080 へアクセスすると、Liftの初期画面が表示される
はじめからユーザ管理とかついているので、sign upでアカウントを作るとユーザ画面が表示される!
速度はなかなかいい感じ
初期はH2Databaseでファイルに保存されてます。

LiftにはMVCでいうControllerの部分が明示的に存在しない
ではどうするのかというと、Viewをメインに考えてSnippetをいうものを使う
Snippetはパーツみたいな感じで、Viewにタグでぺたぺた貼り付けるという感じ、、、であってるかな |-`)

サンプルプロジェクトでは、HelloWorldというSnippetが入っている
src/webapp/index.html内の
<p><lift:helloWorld.howdy /></p>
という部分でスニペットを読んでいる

スニペットの中身は
def howdy = <span>Welcome to helloworld at {new _root_.java.util.Date}</span>

という事なので、画面上には
Welcome to helloworld at Sat Dec 26 16:43:00 JST 2009
と表示されているわけだ!スゲー!

・せっかくなんでスニペットを作ってみる
def sample = <span>日本語テスト 1+1={1+1}</span>

index.htmlへタグを追加
<p><lift:helloWorld.sample /></p>

表示されました!
日本語テスト 1+1=2


ですが、残念な事にSnippetのHotDeployに対応していません・・・
と思ったらやっぱりみんな同じことを考えているようです。

JavaRevelってのとmvn scala:ccを使って実現しています。
・Liftにあるpom.xml(Jettyの設定ファイル)にある scanIntervalSeconds を 0 にする。
・MAVEN_OPTS=“-noverify -javaagent:/path/javarebel.jar” を設定する
・mvn jetty:run して、別のコンソールから同じフォルダで mvn scala:cc する
で、自動的にscalaファイルがコンパイルされて、JavaRebelがリロードしてくれます。

でもやっぱりフレームワークで吸収してほしいなぁ
そこらへんはGrailsの方が便利ですね

Scalaはじめました

勉強会でScalaの紹介があったので、聞きながら試してみた

・Scalaのダウンロード

http://www.scala-lang.org/downloads からMac版をダウンロード
適当な場所に解凍して bin/scala を実行

Welcome to Scala version 2.7.7.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala>

・とりあえずハワロ!

scala> println("Hello World!")
Hello World!

・このままじゃ面白くないので、ファイルにして実行

hello.scala

println("Hello World!")

[yossy@yossy-MacBook]# scala hello.scala
Hello World!

・順調なので、クラスを作ってみる

object HelloWorld {
def main(args: Array[String]) {
if(args.length > 0) {
println("Hello "+args(0)+"!")
} else {
println("usage: HelloWorld {yourname}")
}
}
}

scalac hello.scala
でクラスファイルが出来る(コンパイル遅い気がする)

・クラスファイルを実行

[yossy@yossy-MacBook]# scala -cp . HelloWorld
usage: HelloWorld {yourname}
[yossy@yossy-MacBook]# scala -cp . HelloWorld yossy
Hello yossy!

classファイルだけど、scalaのライブラリが必要なのでそのままjavaで使えるわけではない。この辺はgroovyと同じです。

MVCフレームワークのLiftってのがあるので今度はそれを試してみようかなぁ

2009年12月14日月曜日

前回の続き

・データとURI
データには一意のURIが割り当てわれます。
http://127.0.0.1/${dbName}/${id}
このURIにたいしてRESTする事でDBの操作を行う事が出来ます。

・データの作成
curl -X PUT http://127.0.0.1:5984/baseball/a89c8812a6f9e83f7b8e1848287de338 -d '{"name":"bar"}'
{"ok":true,"id":"a89c8812a6f9e83f7b8e1848287de338","rev":"1-62bc3c4d01e43ee9d0cead8cd7c76041"}

UUIDを指定してデータを入れるのですが、UUIDを作成する手段がない場合は、Couchから取得する事も出来ます。
curl -X GET http://127.0.0.1:5984/_uuids
{"uuids":["a89c8812a6f9e83f7b8e1848287de338"]}

・リビジョン
CouchDBでは、データが更新されると自動的に履歴が残ります。
_revというフィールドに設定される頭の数字がリビジョン番号になります。
先程のデータを更新してみます。
curl -X PUT http://127.0.0.1:5984/baseball/a89c8812a6f9e83f7b8e1848287de338 -d '{"name":"bar2nd"}'
{"error":"conflict","reason":"Document update conflict."}
おっと、エラーです。

更新する際は、対象のリビジョンを指定する必要があります。
curl -X PUT http://127.0.0.1:5984/baseball/a89c8812a6f9e83f7b8e1848287de338 -d '{"_rev":"1-62bc3c4d01e43ee9d0cead8cd7c76041","name":"bar2nd"}'
{"ok":true,"id":"a89c8812a6f9e83f7b8e1848287de338","rev":"2-e3faaaf677273de632db3e628147558e"}

revが2になりました。
Futonから確認するとわかりますが、すべてのリビジョンでの情報を保持しています。





古いリビジョン情報は、CompactDBや、Replicationしたタイミングで消去されるようです。
(残す方法はないのかな・・・)

長くなりそうなので一旦ここまで・・・

MapReduce系DB CouchDBを試してみた その1

いわゆるNoSQLデータベースというやつ、プチGoogleみたいでおもしろそう。
オフィシャルを参考に

・インストール
Macなら、MacPortsで一発簡単
sudo port install couchdb

Windowsは非公式なバイナリパッケージがあるみたい

・自動起動設定
sudo launchctl load -w /opt/local/Library/LaunchDaemons/org.apache.couchdb.plist

・動作確認
curl http://127.0.0.1:5984
{"couchdb":"Welcome","version":"0.10.0"}
バージョン情報もJSON返し :)

・すべてのDBを表示する
curl -X GET http://127.0.0.1:5984/_all_dbs
(curl -X はメソッド(GET,POST,PUT,DELETE)指定)

[] 何も作ってないので空の配列がかえってくる

・DBの作成
curl -X PUT http://127.0.0.1:5984/baseball
{"ok":true}

確認
curl -X GET http://127.0.0.1:5984/_all_dbs
["baseball"]

・もっかいやってみる
curl -X PUT http://127.0.0.1:5984/baseball
{"error":"file_exists","reason":"The database could not be created, the file already exists."}
もうあるから作れんよ、と

・DBの削除
curl -X DELETE http://127.0.0.1:5984/baseball
{"ok":true}

確認
curl -X GET http://127.0.0.1:5984/_all_dbs
[]

・管理画面
実はインストールした時点で管理ツール(Futon)も一緒に入っている
http://127.0.0.1:5984/_utils/
で管理画面が表示されたらOK
Futonへのアクセスはlocalhostではなく、127.0.0.1を使う方が良いらしい



FutonからDBを作ったり、データを登録したりも可能


とりあえずここまで、次回はMapReduceでデータの取得とか
GrailsもCouchDBPluginがあるのでこれもテストしたい

2009年11月18日水曜日

Air2.0Beta!

Air2.0ついに公開されました。

ここからダウンロード出来ます。

色々あって、このアプリを作ってます。
(見た目とかデフォのままなのでいけてないですが・・・)

Adobe AIR Dayで紹介されるのかな?
行くけど今回は喋りません :)

2009年11月17日火曜日

Groovyで時間計算とか

すぐ忘れる・・・のでメモ

JavaだとCalendarとか使わないといけなくて何かと面倒
Groovyなら便利なのがあるよ!

TimeCategory

使い方はこんな感じ

use(org.codehaus.groovy.runtime.TimeCategory) {
def tm = new Date() + 1.days + 25.minute - 2.years
println tm.format("yyyy/MM/dd HH:mm")
}


簡単かつ、わかりやすいよね!

2009年11月16日月曜日

Slim3を試してみた

Slim3がPreviewReleaeされたと言うことなのでGetting Startedをみながら早速試してみました。

・Eclipseのダウンロード
3.5をゲッツ

・まずは日本人なので日本語化
ここからダウンロード

・EclipseにGooglePluginをインストール
http://dl.google.com/eclipse/plugin/3.5 を指定してインストール

・slim3の空プロジェクトをダウンロード
ここから最新版をダウンロード

・ファイル>インポート>既存のプロジェクトをワークスペースへ>アーカイブファイルでダウンロードしたzipを選択

・環境設定>Java>コードスタイル>インポートの編成で java.lang.Math.*に必要な静的インポート数を1に

・環境設定>Java>エディター>コンテンツアシスト>お気に入りで 新規タイプから以下の3つを追加
org.hamcrest.CoreMatchers
org.junit.Assert
org.junit.matchers.JUnitMatchers

・プロジェクト名を適当に変更して、war/WEB-INF/web.xml の以下の値も適当に変更

<context-param>
<param-name>slim3.rootPackage</param-name>
<param-value>slim3test</param-value>
</context-param>

・プロジェクトのプロパティから Javaコンパイラー>注釈処理>ファクトリーパス>JARの追加で lib/slim3-gen-EA1-SNAPSHOT.jar を追加

ここまでやってとりあえず実行可能な状態になったのでとりあえず走らせてみる

The server is running at http://localhost:8080/

と出たのでブラウザでアクセスしてみたら画面が出たよ!


しかしOnlineDemoもみても動作速度が遅い・・・(AppEngineが遅いんだろうけど)

AppEngineにあげるのはGooglePlugin側の設定かな?
次回はここいらへんをちょっとテストしてみたいと思います

2009年11月11日水曜日

SnowLeopardにしてあれこれ

前に使っていたMacBookProがSnowLeopardにアップデートできず(インストール完了後何事もなかったかのようにLeopardが立ち上がる)
、放置プレイだったのですが tyama のお古のMacbook(not pro)を譲り受けたので思い切ってSnowLeopardをクリーンインストールしました。

以下、色々困った事

・ATOK を入れたら textmate で日本語がちゃんと入力出来ない
>ATOKのアップデートで解決

・Java6しか入ってない
ローカルでコンパイル>サーバにアップしたらVersion違いでエラー出たっ!
ココを参考にJava5をインストール
こういう時の為のCIなんだろうけど、ちょっとテストしたい時とかもあるので入れておくと便利

・IPAフォントがインストール出来ない
ココに解決方法がのってました。
.otf を .ttf にするだけ・・・なにそれこわい

・Exposeに設定したFunctionKeyが聞かなくなる
よく見る症状です、いつになったら直るんだろう?
ターミナルから killall Dock で復旧出来るけどすぐダメポになる

でもトラックパッドが想像以上に使いにくくなったので、マウスでExposeしている
久々にコレをひっぱりだした
やっぱりマウスの方が圧倒的にポイント速度が速い・・・隠しているDockが表示されるまでの時間が遅いと感じるぐらいに

*Bluetoothマウスが欲しくなった :)

・64bit起動出来ない
64キーを押しても、plist書き換えてもだめ、なんでじゃろい、proじゃないからか!

・iWork'08 のNumbers が真っ白になって使えない
ココから1.0.3をダウンロードしたら直った

色々あるけど、クリーンインストールしたら死ぬほど快適になった、Winと違ってMacはいつまでも快適!って思ってたけどやっぱりそうでもないのね :(

2009年10月15日木曜日

Grails+postgresでDBチューニング

Grails+postgresでのチューニングで自分がやっている方法をざっくりとまとめ

・postgresからスロークエリの検出をする

postgresql.conf に設定

log_min_duration_statement = 5000ms

上記だと5秒以上かかった処理をログに書き出してくれます。
Hibernateから実行したクエリは以下のような感じで書き出されます。

LOG: duration: 7912.798 ms statement: EXECUTE [PREPARE: select book0_.id as book_1_ from BOOK book0_ where book0_.id=$1]

・クエリのコストを検出する

ログに出力されたクエリが実際にDBで検索にかかるコストを算出します。
SQLの部分( select ~)の前に explain をつけて実際にクエリを実行します。
($1,$2等は実際の値に置き換えて下さい。)

explain select book0_.id as book_1_ from BOOK book0_ where book0_.id=1

すると以下のような情報が帰ってきます。

Seq Scan on book this_ (cost=0.00..32955.18 rows=1 width=2104)
Filter: (id = 1)

0~32955のコストが予想されています。

・indexによるチューニングを行う

10000を超えるようなコストはかなりの負荷になりますので、indexをつけてやります。
(実際にはidにindexは必要ありません、検索対象となる名称とかに置き換えて下さい)

CREATE INDEX id_idx
ON book
USING btree
(id);

再度 explain 付きのクエリを実行すると、以下のような結果が帰ってきます。

Bitmap Heap Scan on book this_ (cost=4.64..98.43 rows=1 width=2104)
Recheck Cond: (id = 1)
-> Bitmap Index Scan on id_idx (cost=0.00..4.64 rows=1 width=0)
Index Cond: (id = 1)

検索対象のフィールドにIndexがついていたため、indexを使って検索し、総コストが 4.64~98.43 となります。
これであればサクサクと検索が実行されます :)

postgresを対象に書きましたが、MySQLでもOracleでもexplainはありますので同じような流れでチューニング可能です。

2009年10月6日火曜日

Air Flex visible=false で領域を確保しないように

良く忘れるのでメモ

通常Air,Flexではlayoutを指定した状態(verticalとかhorizontalとか)で、配置されたオブジェクトのvisibleをfalseにしても、表示が消えるだけで詰めてはくれません。

詰める場合は includeInLayout というアトリビュートを false にしてやればOKです。

2009年10月1日木曜日

WinとMacでコマンドの実行時間を測定する

忘れそうなのでメモしておく、ただし標準で使えるコマンドで

・Mac

time コマンドを使ってその後のコマンドにかかった時間を教えてくれる

time copy /tmp/hoge.zip .

real 0m0.028s
user 0m0.001s
sys 0m0.019s

複数コマンドのトータル結果を知り合い場合は、コマンドを並べたシェルスクリプトを time で実行してやれば良い

test.sh
time copy /tmp/hoge.zip .
time copy /tmp/foo.zip .

time sh test.sh

シェルスクリプトの中のコマンドも全部time書いておけば、一個づつにかかった時間と、最後にトータルの時間がわかる


・Windows

以下のようなbatを作って実行すると、開始時間と終了時間がわかるので引き算するとかかった時間がわかる

echo %time%
copy c:¥tmp¥hoge.zip .
copy c:¥tmp¥foo.zip .
echo %time%

2009年9月14日月曜日

Spring tcServer 超入門!インストール編

GrailsがSpringFrameworkに買収され(今はそのSpringがVMWareに買収されましたが)、Springには元tomcatの中の人達が居るらしく
Groovy/Grailsを動かすにはtcServerが最適らしい
そんなわけでとりあえずインストールしてみた

まずは tcServer の構成から
tcServer = いわゆるインスタンす部分、中身はtomcat
AMS agent = 同PC内のtcServerをまとめる
serverのconfigはここで管理するっぽい

AMS Server = AMS agentをまとめる、apacheのかわりになる部分っぽい

AMS Serverを受け口としてAMS agentへ割り振り、agentがインスタンスを管理している、と・・・そんな感じでしょうか
Server hasMany Manager hasMany Instance な感じ、AMS Server自体は分散処理が必要なのかな・・・?

・まずはMacへインストールしてみる
tcServer-6.0.20.A-SR1-macosx-node.tgz をダウンロード
解凍して install.sh を実行
Macには AMS agent と tcServer とかしかない
どっちを入れるか聞いてくるので、とりあえず両方インストール

・tcServer Instanceを作成
cd tcServer-6.0
./tcserver-instance.sh -s testserver -v 6.0.20.A

testserverという名称で tomcat のバージョンは 6.0.20.A を指定
これで testserver フォルダと tomcat-6.0.20.A フォルダが出来る
デフォルトだと以下のポートが使用されるらしい
HTTP listen port: 8080
JMX port: 6969
AJP port: 8009
Shutdown port: -1

・testserverを起動
testserver/bin/tcserver-ctl.sh start

http://localhost:8080 にアクセスして tcServer の画面が出れば起動は成功

・アプリケーションの配備
単純にデプロイするだけなら testserver/webapps へwarをコピーすればOK

次回はAMSを使ったクラスタや自動デプロイ等に挑戦!

2009年9月4日金曜日

Grails 1.1.1でDomainのsaveについて

Grails1.1.1でたまに .save() でエラーが出る事があります。
MissingPropertyException for "save" って感じなのですが、saveはメソッドなのにプロパティー扱いされてます・・・

これがまた絶対起きる訳ではなく、同じコードでもcleanしたら発生したりしなかったりとやっかいなものです。
現在は修正済みらしく、1.1.2 or 1.2では直るようです。
JIRAはこちら

JIRAにも書いてありますが、HibernateGrailsPluginの初期化がうまくいってないようです。
回避方法としてはドメインの .count とか .list とかを使うと初期化がされるようで、Bootstrap.groovy に以下を追加すれば、
すべてのドメインを初期化してくれます。


import org.codehaus.groovy.grails.commons.ApplicationHolder

class BootStrap {
def init = { servletContext ->
// workaround for GRAILS-4580
ApplicationHolder.application.domainClasses.each { dc ->
dc.clazz.count()
}
}
}

2009年9月3日木曜日

SSHポートフォワーディングでVNC(とかリモートデスクトップとか)

VPNが使えれば悩む事は無いんだけど、そうでもない環境の場合もちょくちょくあるかと思います。
そんな時、SSHが入れるのであればSSHポートフォワーディングを使いましょう。

なんだかフォワーディングとかめんどくさそうな雰囲気が漂っていますが、以外に簡単です。
要領としては、SSHクライアントが特定のポートを受け付ける状態になり、そこへアクセスするとSSH越しに設定した向こう側のPCの特定のポートへアクセス出来るというわけです。
(SSHでログインしたサーバでTCPフォーワーディングが許可されている必要があります)

SSHクライアントが仮想サーバになるようなイメージというのでしょうか・・・
Windowsの場合はTeraTermでココにわかりやすく解説されています
Macであればsshコマンドを使って出来ます、ココに詳しくのっています。

思ったよりも簡単に接続出来ますね :)

2009年8月24日月曜日

fxugに参戦!

fxugの名古屋の第2回勉強会へスピーカーとして参加しました

内容は一からライブコーディングでGrails+BlazeDSの通信を実現するというものです。
今回はFlexのUserGroupと言う事でGrailsが受け入れられるのか若干不安でしたが、アンケート結果を軽く見せてもらったら思ったよりもGrailsへの関心をもっていただけ、楽しんでもらえたようで内心ホッとしております。
これを機にGrailsユーザが一人でも増えれば幸いです :)

今回個人的に興味をもったのが、FlashCatalystとFlashBuilder4です。
Catalystはイラレ(というと東京では怒られるらしい!?)で作ったaiファイルを読み込んで、入力フォームやらシーンやらアニメーションに動作やらを指定してやるとそのままFlashBuilderで読み込んでコンポーネントとして使えますよ!みたいなものです。
インターフェースと実装を完全に切り分けて作る事で、今までエフェクトの動作やシーンの切替(このボタン押すと詳細がここに表示されて〜みたいな感じの)をプログラマが実装していたのをデザイナー側でやれるという事です。

FlashBuilder4はRemoteObjectからウィザードでデータを取得してDataGrid等とマッピング、さらにマッピングしたオブジェクトからフォームを自動生成が出来るという新機能を実装しています。
これはなかなかおもしろいのですが、欲を言えばフォームの動的生成なんかが出来るともっと良いですね!

2009年7月14日火曜日

GoogleMapとジオコーディング(住所検索)について

GoogleMapAPIを登録すると、以下のようなサンプルが表示されます。
デベロッパーガイドを見ていても大体同じような感じです。


<script src="http://maps.google.com/maps?file=api&v=2&&key=xxxxxxxxxxx" type="text/javascript"></script>


これで大体の場合は普通に使えるのですが、ジオコーディングを使う場合は注意が必要です。
ロケールの指定というのがあるのですが、 http://maps.google.com から取得するとこれが日本になっていません。
日本になっていない場合でも大概はうまくいくのですが、以下のように違う場所を表示したりする場合があります。
(ブラウザによっては同じ表示になる場合があるようです、Firefoxでは違う位置になりました)

以下の二つをFirefoxで見ると数値が違うのがわかると思います。(リンクだとうまくいかないのでコピーペーストして下さい。)
http://maps.google.com/maps/geo?q=%E6%BB%8B%E8%B3%80%E7%9C%8C%E8%8D%89%E6%B4%A5%E5%B8%82
http://maps.google.co.jp/maps/geo?q=%E6%BB%8B%E8%B3%80%E7%9C%8C%E8%8D%89%E6%B4%A5%E5%B8%82

ちなみに二つの位置を地図で表示すると、以下のようにずれています。




これはJSON以外にもXMLやJavaScript(GClientGeocoder)で取得する場合も同じです。
日本の指定にはAPIのパラメーラーに hl=ja をつけるか、 http://maps.google.co.jp/maps で取得すればOKです。
日本国内の使用に関しては設定しておいた方が良さそうです。

2009/7/21 ずれがわかりにくかったので修正しました。

2009年7月12日日曜日

Grailsで簡単暗号化! Grails Codecを使ってみよう!

Grailsで暗号化をするのは凄く簡単です。
公式ドキュメントにも乗っていますが、Objectに encodeAsBase64() というのが注入されています。
複合は decodeBase64() を使います。

なので hoge を暗号化すると、以下のコードになります。

def key="hoge".encodeAsBase64() //暗号化
println key
println new String(key.decodeBase64()) //複合化


decodeBase64() では byte配列が返ってくるので、new Stringしてやると文字列として読み取れる形式になります。

これをGroovyだけでやると以下のようになります。

def bytes="hoge".getBytes()
def key=bytes.encodeBase64().toString()
println key
println new String(key.decodeBase64())


ところで、GrailsにはencodeAsBase64()以外にも色々なCodec(encode,decode出来るもの)が用意されています。
(encodeAsHTML()などはscaffoldしたgspにかかれていますね)
更にCodecは自分で追加する事が出来ます。
grails-app/utilsフォルダへ HogeCodec.groovy というファイルを追加し、 encode、decodeというStaticメソッドを用意します。
(Codecファイルを作るスクリプトがあってもいいと思うのですが見当たりませんでした・・・)


class HogeCodec {
static encode = { theTarget ->
return "hoge encode!!!"
}

static decode = { theTarget ->
return "hoge decode!!!"
}
}


これでObjectへ encodeAsHoge() と decodeHoge() が注入されます、簡単ですね!

2009年7月7日火曜日

GlassFishで管理コンソールのURL(コンテキスト)を変更する

リモート管理用で1IP割り当てられた状況から複数のGlassFishを触るという機会があったのでやってみました。

glassfish/domain/domain1/config/domain.xml の以下、赤字部分を編集します。


<web-module availability-enabled="false"
context-root="/gfadmin"

directory-deployed="true" enabled="true"
location="${com.sun.aas.installRoot}/lib/install/applications/admingui/adminGUI_war"
name="admingui" object-type="system-admin">
<!-- System Web Module - DO NOT DELETE! -->
</web-module>


ちなみにポートが自由に使えるのであれば、ポートを変更する方法もあります。
設定 > HTTPサービス > HTTPリスナー > admin-listener のポートを変更して再起動です。

2009年7月2日木曜日

Grails/Groovy勉強会やります

JGGUGの第2回名古屋支部イベント「Grails/Groovy勉強会」でスピーカーをやる事になりました。

詳細はこちら

「Grailsで{さくさく}作るRIA」ですが、内容は入門編です。
続きも考えて居ますので、興味ある方は無料なんで是非ご来場下さい :)

2009年6月22日月曜日

GlassFIsh + Apache(mod_proxy_balancer) で SSL

mod_proxyを以下のように設定


ProxyPreserveHost on
RewriteEngine on

RequestHeader Set Proxy-keysize 512
RequestHeader Set Proxy-ip %{REMOTE_ADDR}e

ProxyPass /test balancer://gf/test timeout=10 stickysession=JSESSIONID
<Proxy balancer://gf>
BalancerMember http://192.168.0.1:38080 loadfactor=10 retry=5 route=instance1
BalancerMember http://192.168.0.1:38081 loadfactor=10 retry=5 route=instance3
BalancerMember http://192.168.0.2:38080 loadfactor=10 retry=5 route=instance2
BalancerMember http://192.168.0.2:38081 loadfactor=10 retry=5 route=instance4
</Proxy>


ポイントはRequestHeaderの2カ所!

そして、GlassFishに以下の2つのプロパティを追加

設定>default-config>HTTPサービス>追加プロパティ

名前:authPassthroughEnabled
値:true

名前:proxyHandler
値:com.sun.enterprise.web.ProxyHandlerImpl

上で設定したProxy-ipとかを利用する為の設定です

参考URL
http://www.manorrock.com/documents/glassfish/proxy-ssl.html
http://docs.sun.com/app/docs/doc/820-7434/6nimnhpqr?a=view
http://docs.sun.com/app/docs/doc/820-7434/gcwrb?a=view

2009年6月15日月曜日

Grails+MySQL Clusterでのトラブル

Grails+MySQL Clusterでのハマったのでメモメモ
(Grailsじゃなくても起こる問題なんだけども)

開発環境時はMyISAMでうまく行っていたのですが、サーバへアップした時にテーブルが作成出来ずにエラーとなりました。
何度やっても特定のテーブルだけが作成されなかったのでMyISAMで作成したDBをダンプアウトしてSQLで流し込んでみたら「Row size too large」だとかなんとか・・・

Google先生に聞いてみたら以下で同様なトラブル事例が
http://forums.mysql.com/read.php?25,33433,33433

Clusterではサイズ指定されたフィールドが 8052バイトを超えるとNGらしいです。

UTF-8では1文字3バイトなのでGrailsのDomain上で、
Stringのフィールドをmapping指定せずに作った場合 varchar(255) で1フィールド辺り768バイト使用されます。
なのでString指定のフィールドを作る場合は極力mappingを指定するようにしましょう。


class Book {
static mapping = {
name type:”text”
}

String name
}

2009年6月11日木曜日

Subversionの移行とバックアップについて

ちょっとSubversionを移行する機会があったのでメモ

SVNを作成
svnadmin create repoName

バックアップの作成
svnadmin dump repoName > repo.dump

バックアップのリストア
svnadmin load repoName < repo.dump

ファイルを丸ごとコピーしてもいけるっぽいけど、環境によってはNGっぽいのでdumpを使う事にしました。

バックアップをする時は、必ずsvnのユーザで実行する事!rootはだめ!
dump した時にエラーが出る場合は repoName/db/log* のファイルが壊れている事があります。
だからと言って log* ファイルは結構大事なファイルなので、さくっと消してはいけません。

そんな時にはリカバリコマンド
svnadmin recover repoName

もちろんこれもsvnユーザで。rootユーザでやってリポジトリ壊れたのはいい思い出・・・

cronで常用バックアップしたい場合は svn-backup-dumps.py を使うと便利!
SVN1.4以降なら一緒にインストールされてます。
ここに詳しい事が乗っています。

こんな感じのスクリプトを作って

DUMP="/subversion-1.4.2/tools/server-side/svn-backup-dumps.py"
BACKUPDIR="/svnbackup/"

for var in `ls -F /svn/repos|grep /`
do
BKSVN="$BACKUPDIR$var"
mkdir $BKSVN
$DUMP -c 10 $var $BKSVN
done


crontab に設定
05 4 * * * root /root/svnbackup.sh

これでrepos以下にあるリポジトリ全部を /svnbackup へバックアップしてくれます、リポジトリが増えても安心!

2009年6月8日月曜日

ありがとう、さようなら

去年買ったシビックを売る事になりました

もの凄く良い車だったのですが、維持が困難になったしまったので仕方なく・・・
思えばノーマルのまま乗り続けたのは今まででこの車だけなんだなぁと、改めて感動を覚えました

久しぶりにサーキットも行って、車を走らせる楽しさを思い出させてくれました

またいつかこんな車に出会えると信じて

今は、ありがとうの気持ちを形に残しておきたいと思います

2009年5月19日火曜日

Grails 1.1.1 でプラグインリポジトリ(認証付き)を使ってみた

Grails1.1.1がリリースされた事もあり、自分プラグインリポジトリを試してみました。

1.1系になり、プラグイン周りが大幅に変わったのはコチラで詳しく解説されています。


では早速実践です!(環境はMacです)


まずはSubversion Clientを1.5系にします(SVNKitの部分で1.5以外はうまく動作しませんでした)
ココから探っていくと過去のバージョンもありましたのでそこから 1.5.6 を入れました。

次にSVNリポジトリを作成します。リポジトリ側のバージョンは1.5でなくてもOKです。(今回は 1.4.2 でテストしました)
サーバ側の設定は何もありません、中身も空で良いです。

開発環境orプロジェクトへリポジトリ設定を追加します。
開発環境に追加する場合は ~/.grails/settings.groovy ファイルへ、
プロジェクト毎に設定する場合はプロジェクトの grails-app/conf/BuildConfig.groovy ファイルへ以下の内容を記述します。

grails.plugin.repos.discovery.リポジトリ名称=SVN URL
grails.plugin.repos.distribution.リポジトリ名称=SVN URL

discovery は取得(list-pluginsやinstall-plugin)、
distribution はコミット(release-plugin)の設定です。

開発環境とプロジェクトの両方に同じリポジトリ名称が設定されている場合はプロジェクトに設定された方が優先されます。

SVNのURLは認証が無い場合はそのまま、http://svnurl/ と記述すればOKですが、今回はBasic認証を使います。
Basic認証を使う場合には https を使用する必要があります。

試しに https://svnurl/ だけ指定して list-plugins するとユーザ名とパスワードを聞かれます。
ですが、これ list-plugins 以外にも run-app 等毎回聞かれます、しかもhttpsのリポジトリが複数あると、すべてのパスワードを毎回聞かれてうっとおしいことこの上ないです。(しかもパスワード入力がマスクされないので丸見えです :p)

ユーザを聞かれないようにするには https://username:password@svnurl と入力しておきます。
ですがこれもパスワード丸見えなので、BuildConfig.groovy に書いておくとチームで使うには不便です。
(とりあえずチーム内で使うには各自の settings.groovy へ書いておくのが得策と思われます)

ここまで設定出来れば準備完了です。
適当な plugin を作成し、releaseしてみましょう。

grails create-plugin testPlugin
cd testPlugin
grails release-plugin -repository=リポジトリ名称

コミットメッセージ等を聞かれて、うまくいけばSVNへプロジェクトがコミットされます。
初releaseの場合はリポジトリに .plugin-meta/plugin-list.xml ファイルが作成されます。
この中にそのリポジトリ内のpluginの情報が記述されます。
ファイルがうまく作成されていたら以下のコマンドを実行して確認してみましょう。

grails list-plugins -repository=リポジトリ名称

先程releaseした testPlugin が表示されれば成功です。

ですが、今 release したローカルのファイルはsvnの管理下にいないので、次のバージョンをリリースするには、
一度アップされた plugin を checkout して、更新後、release-plugin する必要があります。
1回目だけはちょっと面倒です。

最後に通常のGrailsプロジェクトを作成し、insall-plugin 出来れば完璧です。

grails create-app test
cd test
grails install-plugin test-plugin

これでチーム開発をする時に plugin ファイルを共有する必要がなく、
application.properties に plugins.test-plugin=0.1 が記述されているだけで、ファイルがなければ run-app時に自動的にインストールしてくれます!

まだちょっと扱いが生な感じがするのですが機能としては十分使えそうです、プラグインもプロジェクトもスッキリさせましょう!

2009年5月12日火曜日

そろそろMySQL Clusterと向き合う時期が来たのかもしれない その1

普通のMySQLすらまともに使った事の無い状態でのトライです
なんで基本的に間違ってる事があるかもしれませんがご了承を・・・

まずはMySQL Clusterから必要なパッケージをダウンロードしにいく
今回はRedHatにセットアップするので、RedHatのリンクへ

・・・
・・・
・・・
Server、Client、Cluster storatge engine、Cluster storage engine managemen、Cluster storage engine basic tools、Cluster storage engine extra tools、Headers and libraries、Debug Info、Shared libraries、Test suiteと山盛りであるんですが・・・

どれをダウンロードしろと?w

・・・

まーさっぱりわからんのでとりあえず何がどれなのか知る為に漢の中の人が書いてるココを参照

MySQL Clusterには管理ノードとデータノードとSQLノードというのがある、それぞれは以下のように解釈

・管理ノード
他のノード達の管理をしている、バックアップもこいつから実行
管理といっても居ないと動かないわけではなく、ノード達のON/OFFなど本当に管理だけ

・データノード
実データ格納場所、MySQL Clusterは基本的にデータをHDD上ではなくメモリ上で管理する(!)オプションでHDD保存も出来るらしいけど
データノード間でハートビートを送り、タイムアウトすると管理ノードに報告する。ちくり魔め。

・SQLノード
SQLを解析して、データノードからデータを取得する
なんだかよくわからんかったけど、どうやらこれは通常のMySQLという事らしい
MySQLにはRDBMSのENGINEとしてMyISAMとInnoDBが主に使われているんだけど、MySQL ClusterとはこのENGINEの一つとして動作するものらしい!
(ずっとMySQL Clusterというまったくの別物だと思っていたので、ここを理解したらなんだか随分わかりやすくなった)


で、ようやくダウンロードに戻るわけですが・・・イマイチよくわかりませんでしたw
セットアップ後の自分なりの解釈で、

Server SQLノードにあたる部分
Client サーバ上でSQLノードへ接続したり、いわゆる mysql コマンド
Cluster storatge engine データノード
Cluster storage engine managemen 管理ノード
Cluster storage engine basic tools データノードツール?
Cluster storage engine extra tools データノードツール?
Shared libraries 共通のライブラリ

こんな感じ、以下は必要なさそうだったのでダウンロードしてない :)

Headers and libraries
Debug Info
Test suite


2009/5/13 追記
漢の中の人がすでに書いてました :)
これは公式にも乗せるべき内容!


実は内容的にまったく進んでないんですが、MySQL Clusterにはこんな初心者向けな記事があってもいいよね!

次回はセットアップ奮闘編
(本当にやるのかなw Grails+Connector/J(フェイルオーバー)+MySQL Clusterで色々落ちても安心だね!までやったので残しておきたいけど)

Grailsで添付ファイル付きメールを送る

Grailsには公式でMailPluginというのがあり、こいつを使うとDSL形式で簡単にメールが送れます。

ですが、こいつは添付ファイルに対応していません。
ここですでに解決が出ているのですが、公式のバージョンではまだ実装されていないので、自分で拡張してしまいましょう。

grails install-plugin mail
でpluginをインストールし、その中の MailService.groovy ファイルを開きます。

このファイルの中に MailMessageBuilder Class の定義がされているのですが、こいつがDSLを処理している部分になります。
(void to とか void title とかその辺りです。)
ここに attachBytes という添付ファイル名、コンテントタイプ、バイト配列を受け取ってメールに添付する処理を追加してやります。


void attachBytes(String fileName, String contentType, byte[] bytes) {
getMessage().mimeMessageHelper.addAttachment(fileName, new ByteArrayResource(bytes), contentType) }
}


このままだと getMessage した時に、以下の部分が呼ばれます


message = new MimeMailMessage(mailSender.createMimeMessage() )


添付ファイルを送る時は Multipart にしないといけないので、以下のように書き換えてやります

message = new MimeMailMessage(new MimeMessageHelper(mailSender.createMimeMessage(), true ))


あとはメール送信時に attachBytes を呼び出してやればOKです。

def file=new File("test.dat")
// ファイル名に日本語が含まれる場合は文字列をエンコードする必要があります
// 日本のメール環境では iso-2022-jp がまだまだ主流なので、iso-2022-jp を使いましょう
//def title=javax.mail.internet.MimeUtility.encodeWord("日本語ファイル名.dat", "utf-8", "B")
def title=javax.mail.internet.MimeUtility.encodeWord("日本語ファイル名.dat", "iso-2022-jp", "B")

// コンテントタイプはファイルや用途に合わせて変更して下さい
def contentType="application/octet-stream"

mailService.sendMail {
to "test@test.jp"
from "test@test.jp"
subject "添付テスト"
body "添付ファイルを送ります"
attachBytes title, contentType , file.readBytes()
}


と、思ったらMail from Grailsなんてページがあったり、この方法でもファイル添付出来るみたいですね。
↑プロポーザル的に書かれているだけで、実装されているわけではないらしいです

2009/5/13 追記
メールタイトルの文字コードと、Mail from Grailsのページについて、mottsniteの中の人から指摘があったので修正

2009年5月7日木曜日

HudsonをCLI(CUI)で操作する

Hudson CLIとGroovy shellという記事をよんでとても興味深かったので早速試してみました。

自分所に入ってるのが古かったので最新版を公式からダウンロード
前はjarパッケージしてスタンドアローンアプリで動かしていたけど、特別必要もなかったので普通に tomcat に配備

tomcat を起動して http://serverurl/hudson/cli へアクセス
こんなんでましたよっと



リンクから hudson-cli.jar をダウンロードして shell から早速実行してみる


java -jar hudson-cli.jar -s http://serverurl/hudson help

version
Shows the Hudson version
help
Lists all the available commands
groovysh
Runs an interactive groovy shell



とりあえず version と help と groovysh が実行出来るっぽい
記事元の groovy コマンドもばっちり動いて Hudson の instance を取得出来た!
pluginとか作る時とか、サーバから操作する時とか色々出来そうですね

なにより Groovyってのがいいね :)

2009年5月1日金曜日

Grailsで帳票! fop編

帳票、というか組版の部類になると思うんですが、fopでPDFを作成してみました。

帳票というと帳票ソフト+帳票ツールという概念が強かったのですが、
mottsniteさんから
「HTML組む時にGUIソフト使わないっしょ?帳票もGUI使わずにfopでタグ書いたらいいんじゃないの?」
と言われ妙に納得してしまったので、使ってみる事に。

日本語出力までに微妙な所でハマってしまったのでメモっておきます。

・まずはApache fopをダウンロードします。(0.95を使いました)

・Grailsのプロジェクトにライブラリを追加します。
buildフォルダから fop.jar と、libフォルダから以下のファイルを grails プロジェクトの lib フォルダにコピーします。
xmlgraphcs-commons-1.3.1.jar
batik-all.jar
avalon-framework-4.2.0.jar

その他のjarファイルはgrailsが持っているもので補えるので必要ありません。

・FOPの設定ファイルをコピーします
conf/fop.xconf ファイルを適当な場所にコピーして以下のように書き換えます。

<?xml version="1.0"?>
<fop version="1.0">
<base>.</base>
<source-resolution>72</source-resolution>
<target-resolution>72</target-resolution>

<default-page-settings height="11in" width="8.26in"/>

<renderers>
<renderer mime="application/pdf">
<filterList>
<value>flate</value>
</filterList>

<fonts>
<auto-detect/>
</fonts>

</renderer>
</renderers>
</fop>


昔のバージョンではフォントファイルからフォントメトリクスを作成し、その定義をちまちまと書く必要があったのですが、
今はfontsのauto-detectでOSがもってるTTFのフォントが使えるようになります。
(一回目の起動時はフォントファイルを全部読み込むので時間がかかります。)

・簡単なFoファイルを用意します

<?xml version="1.0" encoding="UTF-8" ?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="PageMaster">
<fo:region-body margin-top="3cm"/>
</fo:simple-page-master>
</fo:layout-master-set>

<fo:page-sequence master-reference="PageMaster">
<fo:flow flow-name="xsl-region-body">
<fo:block font-family="Batang" font-size="18pt" text-align="center">
Hello: XSL-FO to PDF
日本語
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>


*font-family は実行するPCに入っている適当なTTFフォントを指定します。
(はじめはMS明朝でテストしていたのですが、なぜかMS明朝はうまく乗らないようです、他のTTFフォントを使いましょう。)

・FopFactoryを定義します。
通常は new FopFactoryでいいんですが、せっかくなのでGrailsっぽくSpringBeanとして登録しちゃいます。
conf/spring/resources.groovy を以下のように書き換えます。

import org.apache.fop.apps.FopFactory

beans = {
def fopFactory=fopFactory(FopFactory){
}
}


これでコントローラーやサービスに def fopFactory とするだけで注入されます :)

・レンダリングを実行します
とりあえずコントローラーにでも書いちゃいましょう



def fop={
fopFactory.setUserConfig(new File("fop/fop.xconf"))
OutputStream os = new BufferedOutputStream(new FileOutputStream(new File("fop/fop.pdf")))

try {
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, os)

TransformerFactory factory = TransformerFactory.newInstance()
Transformer transformer = factory.newTransformer()

Source src = new StreamSource(new File("fop/fop.fo"))
Result res = new SAXResult(fop.getDefaultHandler())

transformer.transform(src, res)
} finally {
os.close()
}

render "ok"
}





素晴らしい!
速度も十分です。
グラフを出したりはまた別の仕組みが必要になってしまうのですが、組版的な細かい調整(長体かけたり、外字使ったり、レイアウト組とか・・・)が出来たり、MarkUpBuilder使ってプログラム的に組んでしまえばデータにあわせて微妙に形をかえるような帳票も出来ちゃいますね!

2009年4月28日火曜日

Grailsで帳票!JasperReport 出力編

めずらしく引き続きJasperReportです。
今回は jasper ファイルから pdf を出力します。

ざっくりコードから!

def report="sample.jasper"
def ds=new JRXmlDataSource("http://localhost:8080/jasper/book/xmllist","/list/book")
def print = JasperFillManager.fillReport(report,[:], ds)
def pdf=new File("test.pdf")
JasperExportManager.exportReportToPdfFile(print,pdf.getAbsolutePath())


reportに帳票ファイルのパスを指定(File型は使えないので注意)

今回はXMLを読み込むのでデータソースにJRXmlDataSourceを作成、前回アクションでxmlを生成するようにしたので、そのURIと、データの基準となるxpathを指定

JasperFillManager.fillReport でレポートファイルと、帳票パラメーター(今回はなしなので空のマップ)、データソースを渡して JasperPrint を作成します。

JasperExportManager.exportReportToPdfFile で出力先のファイルを指定して実行

これでPDFが出力されます。
小さな帳票だったら爆速です!(BIRTと比べて)
ブラウザに表示したい場合は JasperExportManager.exportReportToPdf でPDFのbyte配列がかえるので、これをストリームに返してやればOKです(contentTypeとかはちゃんとセットしてね)

Grailsで帳票!JasperReport 帳票準備編

GrailsでJasperReportの帳票を出力する方法
長いので帳票準備編と出力編に分けます |-`)
XMLを使って出す方法です。
レポートからDB経由して直接引っ張り込む方法もありますが、帳票にあまりロジック的なものをいれたくないので・・・

・Jasperのライブラリをプロジェクトに追加する
公式サイトからjasperreports-3.5.0.jarをダウンロードしてきてプロジェクトの lib フォルダへ突っ込む
PDF出力にiTextを使っているので、iTextと、日本語出力用にiTextAsian.jarとiTextAsianCmaps.jarを入れます。

・DomainをXMLで出力出来るようにする
以下のような感じでxmlを返すアクションを作りましょう。
as XMLは import grails.converters.XML をしてやる必要があります。


def xmllist = {
render(text:Book.list() as XML,contentType:"text/xml",encoding:"UTF-8")
}


・XMLのサンプルデータを取得し、iReportへデータソースの定義をする
上記のアクションにアクセスするとブラウザにXMLが表示されます。(またはダウンロード)
このXMLを保存し、iReportから新規データソースを作成で、XML file datasourceを選択します。



適当な名称と、XMLを指定、Create a datasource using this expressionを選択して xpath を指定します。



・レポートへフィールドをセットする
Field項目の追加で、Descriptionにフィールド名(XMLのノード名)を入れます
追加されたフィールドをレポートへドラッグします
(値が日本語の場合はフォントを日本語フォントに変更します)



Preview を選択するとXMLから読み込まれた値が表示されます。
Previewした時点でテンプレートがコンパイルされ、同名の.jasperファイルが作成されます。
(iReport3.5ではコンパイルの方法がPreviewしか見つかりませんでした・・・)

ここでは日本語がサクっと出るのですが、このままだとPDFにした時に日本語が表示されません。
レポートのXMLを見ると(DesignerとPreviewの間にあるXML)fontタグがあるのですが、こいつにPDF出力用の設定をしてやる必要があります。
(iReport3.5ではここはGUIでは編集出来ないっぽいです)

以下平成角ゴの例です。

<font fontName="Hiragino Kaku Gothic Pro" pdfFontName="HeiseiKakuGo-W5" pdfEncoding="UniJIS-UCS2-H" isPdfEmbedded="true"/>


これで帳票の準備は完了です。
次回はこのjasperファイルを使ってプログラムから帳票を出力します

2009年4月27日月曜日

Grails 1.1 でやってはいけない事(warするとエラーな件について)

とあるGrails1.1のプロジェクトでwarしてTomcatにのっけたら動かないとの事で、、、その時点での1.1.1のSNAPSHOTでやってみたら動いたという情報を元に原因を探してみる事に

結論からいくと、saxonというXSLTプロセッサのライブラリがあると起動に失敗するっぽい
起動時に applicationContext.xml の定義を読む込み所で失敗しているので、ここで使うxmlのparserがsaxonのライブラリと衝突を起こしているっぽい感じ

過去の 1.0.3 とか、1.1.1-SNAPSHOTで動く所を見るとソース上の凡ミスっぽい感じもするけど・・・
(最新の1.1.1-SNAPSHOTにアップデートしたら今度はrun-appも出来なくなった、、、本当に近日リリースされるのだろうか |-`;) )

2009.4.28 追記
最新版はSubVersionではなく、Gitで管理されているもよう、SVNのリポジトリは信頼しちゃダメ!
多分コレ

特に理由がなければ、こちらの方法をを使った方が使いやすいし良いと思います :)

2009年4月21日火曜日

Grails+HiberObjectsでJPAなモデリング

HiberObjectsというEclipseのPluginでHibernate+JPAをGUIモデリングで作れるのですが、これがGrailsに対応していると言う事で使ってみました。

公式サイトはコチラ

最新のEclipseをダウンロードしてきてpluginをセット、Grailsは1.1を使いました。
公式の説明にしたがってHiberObjectsを有効にしていきます、公式のは少し古いみたいでオプションが一部違いましたが、
特に気にするような項目もなかったのでそのまま続行。

公式には Deselect Add Hibernate libraries とありますが、後でHibernate関係でライブラリが見つからないよとエラーが出るのでチェックを入れておきました。
(1.1からはHibernateが完全なPluginとなり、GRAILS_HOMEのlibフォルダにHibernate系のライブラリが入らなくなった為)

設定画面はこんな感じです。




HiberObjectsを有効にしたら、クラスダイアグラムを作ってUMLを描いていくとJavaコードと、hibernate.cfg.xml が生成されます。


あとは generate-all なり、scaffold=true なりして run-app すると普通に CRUD が出来ま、、、、せんでした |-`)
Create,Read,Deleteとリレーション系はちゃんと実装されてるんですが、Editでエラーになります。
ソース見たら自動生成されるファイルに version がありませんでした(´・ω・`)
(クラスに手動で Long version フィールドを追加してやれば CRUD できました)

他にもクラスダイアグラムで削除したクラスやインターフェースが生成され続けるとか、まだまだ微妙な所もあります・・・
Groovyで普通のドメインみたいに作ってくれてUMLが描けるのかと思ってwktkしてたのでちょっと残念、でもGrailsに対応しようとしてくれる辺りが素敵です、今後に期待!

2009年4月20日月曜日

TextmateでGrailsを開発する5つのステップ

GrailsのIDEでは現在以下があります。

・Eclipse
いわずがなとも。Groovy Pluginを入れておくと便利。
だけどGroovyはダイナミックだからJavaほど恩赦は受けられない。

・NetBeans
Grailsへの対応を結構しっかりやっている。
けどコマンド系(run-app とか create-controller とか)の処理はイマイチな気がする。
なんかタスクがうまく落ちなかったりする。

・IntelliJ
無料お試し期間でしか使った事ない |-`)
一番公式な感じ?
高いのであんまり興味無し

と、いくつかあるのですが、どれも重いんですよねぇ
開発はサクサク動かしたいもんです。

というわけでMacな人にはTextmateをオススメします。
Textmateは有料ですがサクサク動いて色々とカスタマイズする事で凄く便利になります。
Grails向けのおすすめカスタマイズを5つ紹介します。

・日本語表示
textmateはデフォで日本語表示が出来ないので、ココらへんを参考に日本語フォントを入れて表示出来るようにしましょう
はじめはつぶれた日本語に違和感がありますが、慣れるとなんてことないです、むしろ幅が揃って良いという気分でいましょう

・Groovy Grailsバンドル
.gsp 表示のシンタックスハイライトや、便利なスニペット(rt[tab]で render(text:"") とか)がつまってます
ココからダウロードできます

・Groovyバンドル
.groovy 表示のシンタックスハイライトや、次のRun Selected Snippetの為にいれておきましょう
ココからダウンロードできます

・Run Selected Snippet
Groovyバンドルの機能の一つです
選択した部分の Groovy を実行できます
GroovyではJavaのクラスへいくつかの便利な機能が付加されてます、詳しくはGroovy JDKにのってますが、
これらの挙動等をちょっとテストしたい時に最適です

例えばテキストファイルの中身を改行でループして、タブ区切りにした1個目の値をごにょごにょしたいな〜と思った時に、
コントローラーを通してやったりせずに、Groovyファイル上の適当な場所に、その部分のコードだけを書いてちょこちょこ動かして確認すれば良いのです


def infile=new File("test.csv")
infile.splitEachLine("\t") { line ->
println line[0]
}


この出力は通常、ウインドが開いてhtml表示されるのですが、ちょこちょこ動かしたい場合はウインドをいちいち閉じるのがめんどいです
Bundle Editorから Run Selected Snippet を見てみると、 exit_show_html となっている部分が2カ所あります
これが通常の出力になってますので、これを exit_show_tool_tip に変更してやります
すると、 tooltip として結果が表示され、ちょっと動かしてやれば消えるのでサクサク使えます

ただ1画面ぐらい出力がされると tooltip では不便です、でもって exit_show_html の出力は html が解析されてしまうので、htmlを見たい時には不便です
なので新規ドキュメントとして開いてやりましょう
今度は exit_show_html の部分を exit_create_new_document に変えてやればOKです

exit_show_tool_tip で tooltip 表示
exit_create_new_document で 新規ドキュメント表示

大事な事なので2回言っておきます :)
この二つを作っておけば大体のケースには対応出来るでしょう。

・リファレンスリンク

Groovyバンドルには Groovy JDK というGroovyの拡張部分がわかるAPIを開くコマンドが追加されます
Grailsでは Groovy 以外にも色々なフレームワーク、ライブラリが使われていますので、これらもサッと開けると便利です
Groovy JDKのコマンドをコピーして、URLの部分を http://grails.jp/links.html に変えましょう
Grails関連のAPI等がざっくり見れます :)




アジャイルなフレームワークにはアジャイルな開発環境を。
これであなたもGroovy!なGrailsライフをおくれる事間違い無し!

GlassFishとBirtの切ない関係

GlassFIshが謎の停止をするので色々とさぐっていったらBirtで帳票を出した時に止まるっぽい

Birtの負荷かな?と思ってJettyとTomcatでアホのように負荷をかけてみたけどまったくとまる様子がない。
というかGlassFIshでは起動直後でも5セッションで帳票を出すと止まる・・・
4セッションだとほとんど止まらない、なんじゃこりゃ

Birt側の問題かと思って最新版に乗せ変えたりもしてみたけど状況は変わらず
うーん、おとなしくjasperReportにしようかなー、Birtである必要性もないし・・・

なんかわかったら続報を入れます

4/23 追記
GlassFish v3の最新版では正しく動作しました
ただしv3ではメモリ関係がv2より厳しいようです、特に -XX:MaxPermSize の指定は必須です

GlassFIsh v3とTomcat、JettyでOKとなると、v2.1に何か衝突する問題がありそうです
Sunからはv3ではまだCluster等が出来ないので本番環境はv2.1を推奨との事ですが、この状態ではv3を使わざるを得ない感じですね・・・
結局しばらくClusterは上位(Apache等)で処理してやるのが良いかもしれません

2009年4月14日火曜日

Grailsで帳票!JasperReport ざっくり評価編

Javaで帳票といえば長い事BIRTを愛用してきたんだけど、食わず嫌いもよくないと言う事で有名なJasperReportを使ってみた、せっかくなんでGrailsで。

まずJasperReportの仕組み。

jasperReportは jrxml というXMLファイルをコンパイルして jasper ファイルを生成して、そこにパラメーターやらデータソースやらを与えて帳票を出力してくれる

出力形式は XLSやPDF、HTML、CSV等が出せる(XLSはPOI、PDFはiTextを使用)

XMLファイルを作成するには iReport というGUIソフトがある
iReportには Classic 扱いの 3.0 と 現行の 3.5 がある
3.5 はNetBeansベースのアプリ(NetBeans用のPluginもある)でマルチプラットフォームなので良さげな感じだが、
Classicに比べると設定出来る項目が少なかったりする
でもMacな自分には選択肢がないので設定出来ない項目はXMLに直接書く事にする :(

一応メニューもマルチランゲージになっているが、ほとんど英語
とりあえず iReport を立ち上げて適当に帳票作ってみて Preview すると日本語もちゃんと通るっぽい

ざーっくり使ってみた感じ、BIRTとの比較等
レポート的に出来る事、出来ない事の比較はあんまりしてないです、とりあえずJavaで帳票出すって所を視野に入れての感想です

ここが○
・データソースがレポート内部と外部がちゃんと別れている所
XMLをURLから動的に生成していたので、BIRTではデータソースから動的に設定する必要があった
そうするとサンプルデータの準備も面倒だし、動的なURLを解析してXMLをパースしてくれないので、設定に不便だった・・・
iReportではアプリ上に別データソースとしてサンプルファイルをセットしておけばいいのですごくらくちん!
データソースを複数用意しといて切替も簡単、実際にコードから生成する時もデータソースを別であてるだけなので、これは凄くいい!

・ファイルがコンパイル出来る
xmlファイルをコンパイルにしてjasperにしておけば印刷時にコンパイルがいらないのでちょっと早いかも?

・テーブルの部分が別エディタとなっている
BIRTでは同じ帳票上でグリッドとか細かく触らないといけない&重たくて反応が遅れるのでイライラする
でも使いかっては今の所BIRTの方が良い(なれてるだけか)

・プログラムに組み込むのが簡単
BIRTではライブラリも含め色々と仕掛けが必要だったが、JasperReportはいくつかのライブラリいれるだけで後はソース上からさくっと作れた、そのままストリーム返しも出来そうだしいい感じ

・PDF周りの設定がしっかり出来る
PDF上のフォントのエンコード、フォント毎にPDFヘの埋め込みするしない、
PDFのバージョン、セキュリティ関係などなど今なら指定し放題!
BIRTではあるのかもしれないけど、触ってる範囲では出来ないっぽい

ここが×
・幅の%指定がない?
BIRTでは大きさに%指定ができ、ものによって大きくなったり小さくなったりが出来たがjasperReportではないっぽい

・iReportが微妙すぎる
NetBeans版は色々と微妙・・・まだこれからなのかな、Classic版を使ったらもっとハッピーになれるのかしら


次回はBIRTでXMLから帳票を出力しているのがあったので、XMLから帳票を作ってみる編
(ああ、次回ネタが溜まりすぎ・・・)

GroovyのURL Classが素敵すぎる件について

以前、別のURLのデータを取得するのにhttpBuilderを使ったり、httpClientを使ったりしてごにょごにょ書いてたんですが、
mottsniteさんがボソっとURLのgetTextでとれるよ。と言っていたので試してみた。


def url=new URL("http://www.yahoo.co.jp")
println url.getText()


( ゚д゚)

(つд⊂)ゴシゴシ

(;゚д゚)

(つд⊂)ゴシゴシ
  _, ._
(;゚ Д゚)ぁぁぁああぁぁ!?

なにこれ、素敵すぎます。
まだあんまり試してないけど、日本語もすんなり通るし、すげぇ。

ストリームしてファイルダウンロードもいけるみたい。
RESTしたいとかには答えられないのかもしれないですが通常使用ならこれで十分っぽいですね。

FileのgetTextもそうですが、こういうのを見るとまさにGroovy!って感じしますね :)

2009年4月13日月曜日

GrailsのServiceでServletContextを使う

もの凄いピンポイントネタですが。

GrailsのController上ではServletContextが勝手に注入されてます。
Service上では注入されてません、そしてSpringBeanでもないので注入も出来ません。
なんか簡単にとる方法ないのかなーと思ってググったら「コントローラーから渡したらええんちゃうん?」みたいな答えしかなくてしょんぼり。
サービスだけで使いたいのよ、BlazeDSとかWebサービスとかさ。

で、grailsApplicationは注入可能なので、こっからたどって取得します。

def grailsApplication

で grailsApplication を注入して、そこからparentのcontextを取得し(SpringのXmlWebApplicationContext)、そこからServletContextがとれます。

def sc=grailsApplication.getParentContext().getServletContext()

やったね :D

GrailsのServiceでServletContext

2009年4月9日木曜日

クエリチューニングについて本気出して考えてみた

Grailsでアプリを作っていると、O/Rマッピングに頼りっぱなしで、重い所だけたまにHQLを書いていたのだが、
さすがにDBの規模が大きくなるとそうも言ってられないよなーと思い、クエリチューニングに乗り出す事にした。
(indexの最適な付け方も良くわからないし :D )

まずは現在のボトルネックを探す。
今までは体感とシステム上で時間を計測してたけど、DBの事はDBに聞けって事でログ解析をする事に。
ここらへんを参考にした)

postgresのログ解析には pgfouine と pqa というのがあるらしい、前者は php、後者は ruby だ。
これはもちろん pgfouine だろう! php も ruby もよく知らないけど groovy 好きっ子としては ruby に行ったら負けかなと思っている。

ITProの記事を参考に、postgres のログを出力する設定をする

んで pgfouine を実行・・・!しようと思ったら動かない。GDというライブラリが必要らしい。
Macにデフォで入っている php にはこれが組み込まれていない。調べてみると MacPorts でインストールすると簡単らしい。
ということで MacPorts から php をインストール、、、長い、、、長い、、、しかもCPUフルに使いやがる、そういう事は先に言ってくれと。

無事インストールが終わった所で pgfouine を起動してみる。

php pgfouine.php -logtype stderr -file log/postgresql-xxxx-xx-xx_xxxxxx.log -format html-with-graphs -report vanfu_sql.html=overall,hourly,bytype,slowest,n-mosttime,n-mostfrequent,n-slowestaverage,n-mostfrequenterrors,tsung


とりあえず出力オプション全部付けてみた :p



おー、なんかかっこいいですね!
ちょっと試しで3分ほど適当にシステムを稼働させて集計した結果、SELECT件数が 4,179、、、うーんO/Rマッピングが遅いと言われるのがわかります。
まあ逆に考えれば1クエリ0.01秒の改善でも3分あたり40秒もの改善になるって事ですね。

とりあえず現状の確認方法まで
次回はGrails向けのチューニング方法をまとめようと思います。

2009年4月7日火曜日

GrailsでblazeDSプッシュ配信!その1

blazeDSといえばプッシュ機能がついていますが、grailsのflex pluginでは定義されてないので使う事が出来ません。

せっかくあるんだし、サーバから一斉にメッセージ配信とかなんかカッコイイ(ここ重要)ので実装してみました。
まずは plugin を改良して streaming と polling の定義を追加します。

service-config.xml を編集します。

services の中に以下の定義を追加。

<service id="message-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
</adapters>

<default-channels>
<channel ref="grails-streaming-amf"/>
<channel ref="grails-polling-amf"/>
</default-channels>

<destination id="sb-1" />
</service>


*デフォで入っている default-channels が services 全体になっているので、はじめから定義されている remoting-service の中に正しく入れてやる

desitination ってのが接続するキーになります、このタグの中にある security って項目を使うと別のユーザ管理と認証が出来ます。
(acegi と連動出来たら素敵ですが、とりあえず認証無しで)

channelsに以下を追加

<channel-definition id="grails-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
<properties>
<idle-timeout-minutes>0</idle-timeout-minutes>
<max-streaming-clients>10</max-streaming-clients>
<server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis>
<user-agent-settings>
<user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="1"/>
<user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="1"/>
</user-agent-settings>
</properties>
</channel-definition>

<channel-definition id="grails-polling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>4</polling-interval-seconds>
</properties>
</channel-definition>


FlexPlugin では GrailsBootstrapService というクラスが BlazeDS の起動時に読み込まれるので、ここで MessageClientListener を登録してやります。


MessageClient.addMessageClientCreatedListener(new ClientWatcher())


ClientWatcher は MessageClientListener を implements したクラス、サンプルでこんなのを用意してみました。


package org.codehaus.groovy.grails.plugins.flex;

import flex.messaging.MessageClient;
import flex.messaging.MessageClientListener;

public class ClientWatcher implements MessageClientListener {
/**
* クライアントが接続したときに呼ばれる。
*/
public void messageClientCreated(MessageClient msgClient) {
println "connect client"

// 自身をクライアントの切断を監視するリスナとしても登録する。
msgClient.addMessageClientDestroyedListener(this);
}

/**
* クライアントが切断したときに呼ばれる。
*/
public void messageClientDestroyed(MessageClient msgClient) {
println "disconnect client"

// 明示的にセッションを破棄する。
msgClient.getFlexSession().timeout();
}
}


でもクラスを直指定はいけてないので、Acegi風にDefaultConfigで対応するクラスを乗せ変えられるようにしてみました。


// Configのロード
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader())
ConfigObject config
ConfigObject flexConfig
try {
flexConfig=new ConfigSlurper().parse(classLoader.loadClass('FlexConfig'))
} catch(Exception e) {
}

if(flexConfig) {
config=flexConfig
} else {
config=new ConfigSlurper().parse(classLoader.loadClass('DefaultFlexConfig'))
}

// クライアントの接続を監視する
def className="${config.flex.blazeDs.messageClientListener}"
def clientListener=classLoader.loadClass(className).newInstance()
MessageClient.addMessageClientCreatedListener(clientListener)


ここをやっている時、Class.forName() でエラー出てハマっていたので Google先生に聞いてみたら自分が教えてくれた あるあるw
でも GroovyClassLoader を定義してるんでそっちを使ってみた

これで下準備は完了!
次回は接続&メッセージ送信編

この件の事もあるし、要望あれば plugin 公開してもいいかな・・・)

2009年4月6日月曜日

マカーがSubversionを1.6へ移行する道程

Grailsが1.1になってplugin repositoryを設定出来るようになったりして使ってみようと思ったんだけど、どうやらSubversion1.6でないとだめらしい
(Macにデフォで入ってるのは1.4.4なわけですよ)

1.6の新機能詳細はこちら
Mac用のバイナリがここにあるので、これをインストール

/usr/bin/svn を1.6に置き換え、既存のプロジェクトを操作してみる・・・
特に問題無し、.svnの中身は自動でアップグレードしてくれるらしい

ただし下位互換が無いので、一度プロジェクトを1.6にしてしまったら全ユーザが1.6にする必要あり!

・その他、Subversionを使ってたアプリの設定変更
EclipseのSubclipseを1.6用のものに置き換え(アップデートサイトが1.4.x系とは別なんで注意)
Textmateの Preferences > Advanced > Shell Variables の TM_SVN を 1.6 の svn のパスに変更(ここに設定してあったのすっかり忘れてた)

2009年4月3日金曜日

merapiがもたらすAirとJavaの素敵な関係

Air(Flex)でJavaを呼び出すという夢のようなライブラリが登場したようです。
まだベータですが試してみましたのでつらつらと書いていきます。

参考
公式サイト
マイコミの紹介
javaとairを繋ぐmerapiを使ってみた。


まずはJava側の実装から



merapi本体を解凍した中にある framework/java/libs にあるのがJava側で必要なライブラリ
適当なクラスを作って、IMessageHandler を implements する

public static void main の中で Bridge クラスに、自身を regist する


public class MerapiTest implements IMessageHandler {
public static void main(String[] args) {
System.out.println("start");
Bridge.getInstance().registerMessageHandler("merapiSample", new MerapiTest());
}
}


第一引数でBridgeに登録するID(タイプと呼ぶらしい)、第二引数が自身のJavaクラスのインスタンス

flexから呼ばれた時に handleMessage がcallされるのでこれをクラスに書いておく(インターフェース定義されてます)


public void handleMessage(IMessage obj) {
try {
System.out.println("flex > java :"+((Message)obj).getData());
Message response = new Message("merapiSample", "hello merapi");
Bridge.getInstance().sendMessage(response);
} catch(Exception e) {
System.out.println("Caught Exception");
}
}


IMessageというのがFlexから受け取るデータ、MessageにキャストしてgetDataすると中身を取得出来る。
System.out.println("flex > java :"+((Message)obj).getData());

void なんで return値はなし、Flexに情報を返したい場合は Bridge の sendMessageを使う。
Messageの第一引数にregistしたのと同じIDを指定、第二引数に送りたいデータをセットする。
Message response = new Message("merapiSample", "hello merapi");
Bridge.getInstance().sendMessage(response);

続いてFlex側の実装



merapi本体を解凍した中にある framework/flex/libs にあるのがflex側で必要なライブラリ

まずはBridgeのインスタンスを作成する

<merapi:BridgeInstance id="bridge" result="handleMessage(event)" />


こっちはresultのfunction名を指定出来る、Javaと同じにしとといた方がわかりやすいかもね!

メッセージの送信は以下のように

var message:Message = new Message("merapiSample","from flex");
bridge.sendMessage(message);


MessageクラスはJavaとおんなじ使い方でOK

実行方法


まずは java のクラスを起動してやる必要がある
起動して regist した時点で listen 状態で待機される

この状態でFlexを起動してやると、メッセージを送信出来る
Flexが終了した時点でJavaも落ちる

欠点はJavaを起動する必要がある所かな・・・
終了は一緒に終わってくれるので問題なさそうだけど、Airの起動時にJavaが動いてないとエラーになるんで
なんとかしてJavaを起動してAirを起動するような仕組みが必要

うまく使えばクライアントサイドで今以上に色んな事が出来そうですね!
Grailsとの絡みで考えると、Grails1.1からGORMが単体で使えるようになっているのでsqliteを使った生なDBでなく、GORMを使ってHSQLとかでクライアントDBを実装出来たら素敵な気がする!

2009年4月2日木曜日

Airで画面解像度の取得

Airアプリケーションでユーザの画面解像度を取得する方法、忘れそうなのでメモ

Screen.mainScreen.visibleBounds

返り値はRectangle、macの場合 x , y , w , h で x , y はドックとメニュー分の位置がくるので、
領域として使えるのが w と h で、実際の解像度は x+w , y+h で取得可能。

拡大/縮小させたいメインコンテンツを%指定して作っておけば画面サイズにあわせて自動的にフルスクリーンになるアプリが作れそう。

と、思ったけど最大化ボタンを使えばいいじゃん・・・
ご丁寧に maximize() なんてメソッドもありました。

・・・まぁ何か使う時もあるでしょう!

2009年3月30日月曜日

Grails 1.1 warしてみた

Grails1.1でwarしたものを乗せてみた

tomcat 5.5.23 > ×
tomcat 5.5.25 > ×
GlassFish 2.1 > ○

lib関係かな・・・とりあえずメモ、判明したらまた続報入れます

[追記]
tomcat 6.0.18 > ○

6系も安定板出てしばらく立つしこれを機に6へ移行した方が良さそうですね。
メモ
5.5.x > 6.x migration
http://tomcat.apache.org/migration.html

2009年3月26日木曜日

Grails1.x > Grails1.1への移行

Grails 1.0.5 のアプリを Grails1.1 へ移行した時に起きた問題。メモメモ。

とりあえずざっくり grails update をしてみる。
SVNの差分で見てみるとコマンドで変更される内容はたいしてないみたい。
application.propertiesに plugins.hibernate=1.1 が追加されてる、この辺の話しはここで詳しくのっている。


・pluginを読み込まない
pluginの置き場所が変わったため、upgradeしただけでは既存のpluginを読み込んでくれない。
これは 1.1 に追加された BuildConifg.groovy というファイルを書いてやる必要がある。

grails-app/conf/BuildConfig.groovy を作成し、以下のような感じで設定してやる。

grails.plugin.location."pluginName"="plugins/pluginName-version"


ダブルクォートは重要、groovyなんで無いと引き算扱いになってまうよ :)
とりあえず移行ならこれでいいけど、pluginの管理は別リポジトリで自動バージョンアップとか素敵な感じになってるので将来的にはそっちに移行した方が良い。


・xercesImpl.jar が無くなった。
今まではGrails本体のlibフォルダにXercesが入っていたのですがこれがなくなりました。
なのでXercesを使ってたアプリや、Xercesを使っているpluginをいれているとNoClassDefFoundErrorになります。
以前のバージョンからコピーするか、本家から落としてきてアプリケーションの lib フォルダにいれてやりましょう。

・起動時にエラーが出る

以下のようなエラー
ERROR commons.DefaultGrailsControllerClass - The allowedMethods property in ほにゃららController should be declared static. The non static version is supported for now but has been deprecated and may not work in future versions of Grails.

allowedMethods が def から static になったからこのままだと近いうちに使えんくなるよ、と。
単純に def を static にしたら出なくなりました。



とりあえずこれで動作しました。

2009年3月19日木曜日

GrailsCodeReading in 名古屋!

というわけで参加してきました。

お題は「Grails-1.1を斬る!Grails-1.1からのチーム開発」
1.0シリーズ→1.1で結構仕組みが変わっています。
毎度恒例の速度アップやら、GORM(GrailsでのORマッピング)のかゆい所に手が届くようになったとか、正常進化ですね。

もうなんかすげーいっぱい変更点あるんで、ちょっと気になった所だけピックアップ

・<g:form> にuseToken="true" をつけて、受け側の action で以下のように拾える


def save = {
withFormat {
//保存処理
}.invalidToken {
render "二度押し禁止!"
}
}


なかなかいい感じ。だけど画面上には invalidToken 側の処理しか返らないので、スルーして正しい結果を表示ってのは自前実装しないといけない。

・work_dirを選べるようになった
今更感もあるけど、svn とか使ってるとプロジェクトフォルダを trunk とかにしてると、work_dirがかぶってしまう問題があった。
( ~/.grails/{version}/projects/{projectFolder} に固定されていた)
かぶると class とかが入り乱れてまともに動かない状態に・・・
これを BuildConfig.groovy ファイルで好きな場所を指定出来るようになったので、安心して実行出来るようになりました。

・別リポジトリの対応
plugin系で本家のリポジトリ以外に、自前で指定したリポジトリを追加できます。
これを使うと、公式にあげれない/ない plugin を管理出来ます。
さらに1.1では自動インストール/アンインストールがあるので、更新したよーとか最新版いれてーとかしなくても勝手にやってくれる!

2009年3月13日金曜日

FileMakerへのJDBC接続

FileMakerはODBCとJDBCで外部からデータを操作出来るらしい。

JDBCいけるならGrailsでFIleMakerPluginとか作れるんじゃね?という事で接続してみるテスト

まずはJDBCドライバを探す・・・ってここから情報すくなっ
なんか途中のバージョン(7ぐらい?)からSequeLinkDriverで接続するようになったらしい

今回のターゲットは9なのでそれ用のドライバを探す・・・
あ、あったあった、てか公式にあった orz
「FileMaker Pro 9 評価版用 FileMaker ODBC & FileMaker JDBC ドライバ(Mac OS X)」ってのをダウンロード

その中にインストーラー(sljcinstaller.jar)があるのでそれを起動してインストールしていく・・・
インストールした先にはいっぱいファイルがあるけど、とりあえず目的のファイルは driver/lib/sljc.jar

で、なんやかんや試してみるけど綱がらない・・・
どうやらFileMakerProでは localhost からしか接続出来ないらしい :(
MacからODBCではうまくいかないしセットアップも大変になるので、同マシンで動かして外からクエリうけて実行出来るみたいなのでいいや、と思いつつ設定。

FileMaker起動して、JDBC/ODBCの共有をONにして、2399ポートがあいてるのを確認。

そしたらJDBCドライバをロードして、
Class.forName("com.ddtek.jdbc.sequelink.SequeLinkDriver")

Connectionで接続キター!
Connection con = DriverManager.getConnection("jdbc:sequelink://localhost:2399","user","pass")

2009年3月11日水曜日

Grails Flex Pluginの罠

FlexPluginを使うとサービスでのBlazeDSがめっさ簡単になるんで重宝していたのですが、今日はこいつにやられました。

run-app しているときはシレっと動いてたのですが、warしてGlassFishにのっけてみたら web.xml が DTD にはじかれて登録出来ない・・・
で、調べていったら FlexGrailsPlugin.groovy で注入している所で servlet にたいして display-name を設定しているのが問題っぽい。
これをはずして再度 war したら何事もなく動きました。

余談ですが、GlassFishでWebアプリケーションを配備する時は war のサイズがあんまり大きいとうまくいかないみたい。
なんらかの方法でサーバへファイルをアップし、「Application Server からアクセス可能なローカルのパッケージファイルまたはディレクトリ 」を使うのが良いみたい。

grailsアプリを使う上では glassfish v3より glassfish v2.1の方が早くて安定している気がする・・・
Cubbyでもv2のが相性が良いみたい。 v3はもうちょっと様子見かなぁ

2009年3月7日土曜日

GrailsとRESTのただならぬ事情

GrailsでRESTfulなWebアプリを作るのは凄く簡単です。

URLMappingで以下のように振分けが出来ます。

"/rest/$id?"(controller:"rest"){
action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"]
}


これで /rest に来たアクセスはメソッドによりアクションへ振分けされます。
GET(普通にブラウザで開いたり)した場合は show アクションへ、POST(フォーム送信とか)なら save アクションへ飛ばされます。

詳しくはIBMの記事を参照下さい。

ではGrailsでRESTfulなサービスを使用するには、というとデフォではそのような機能はありません。(多分)
ここで前に使ったHTTPBuilderを使おうと思ったのですが、こいつがGrailsと組み合わせてしまうと思うように動かないメソッドがあったりします・・・
http.request(GET,TEXT) { req -> }  とか・・・ responseが正常に取得出来ません :(

HTTPBuilderは中でApache HttpClientを使ってるだけなんで、こいつを直接使う事にしました。


def client = new HttpClient()
def getMethod = new GetMethod("http://localhost:8080/restProject/rest/1")
getMethod.setRequestHeader("Accept", "text/json")
client.executeMethod(getMethod)
def result=getMethod.getResponseBodyAsString().toString()


これでGETを実行し、結果をStringで受け取れます。
それぞれ PostMethod、PutMethod、DeleteMethodが用意されているのでそれらに置き換えれば他のメソッドを実行出来ます。

RESTってHTTPプロトコルの標準な機能なのでクライアントに特別なライブラリ等を追加する必要がない反面、WSDLのようにメソッドの仕様や型の制御などが作り手次第になってしまうのがちょっと難点な気がします。

でもWSDLと違って、認証等はacegi pluginいれてbasic認証使えば比較的セキュアかつ統合された作りが簡単に出来るのは良いですね!

2009年3月2日月曜日

GrailsでMySQLに接続

特に書くほどの事でも無いですが一応メモ・・・

MySQLへの接続は Connector/J で行いますんで、MySQLのサイトから接続するDBバージョンにあわせたConnector/Jをダウンロードします。
今回は 5.1 なので mysql-connector-java-5.1.7.tar.gz をダウンロードしました。
こいつを解凍して mysql-connector-java-5.1.7-bin.jar を grails の lib フォルダに入れます。

まずはDB側の設定。my.cnf に以下を入れておく。

default-character-set=utf8

MySQLAdministrator の設定画面から行くと↓のへん


DBを先に作っておき(今回はdbnameという名称で仮定)、 conf/DataSource.groovy の設定を

pooled = true
dialect = org.hibernate.dialect.MySQLDialect.class
driverClassName = "org.gjt.mm.mysql.Driver"
username = "root"
password = ""
dbCreate = "update"
url = "jdbc:mysql://localhost/dbname?useUnicode=true&characterEncoding=UTF8"

以上のようにして起動すればめでたしめでたし。

2009年2月27日金曜日

mySQLレプリケーションのセットアップ

もっぱらpostgresだったのだけんども食わず嫌いも良くないのでmySQLをもしゃもしゃしてみた。
このへんを参考に。

・セットアップ
Macはパッケージがあるので簡単セットアップで完了。
postgresでいう所のpgAdminはmySQL GUI TOOLというのがある。

サーバ管理系とクエリ/データ処理系とで以下の二つに別れている。

・MySQL Administrator
DBの起動/停止、DBの作成、テーブルの作成、ユーザの作成、バックアップ/リストア等がGUIで出来るツール

・MySQL QueryBrowser
クエリの実行、テーブルの中身をざっくりみたい場合もこっち


サクっと起動した所で、レプリケーションの設定。
スレーブ側からマスタへ接続する為のユーザを作成。

mysql> GRANT REPLICATION SLAVE ON *.* TO repl@'192.168.20.0/255.255.255.0' IDENTIFIED BY 'xmldo';

repl / xmldo というユーザが作成される。
この接続は 192.168.20.0/24 からのみ接続可能。
MySQL Administratorから作る事も出来る。

マスタ側はログをバイナリで出力する必要がある。
また、レプリケーションする際には、すべてのDBへ固有のserver-idが必要となる。
マスター側のmy.cnf

[mysqld]
server-id=10
log-bin


スレーブ側のmy.cnf

[mysqld]
server-id=11
master-host=192.168.20.15
master-user=repl
master-password=xmldo


設定ファイルを書き換えて再起動でレプリケーション完成。あら、アッサリなのね。
ではトラブルを想定して実験をしてみましょう。

・スレーブが停止中にマスターにデータが書き込まれ、その後スレーブが復帰。
>スレーブ復旧後に、追加したデータ問題なく挿入されました。

・マスターが停止中にスレーブにデータが書き込まれ、その後マスターが復帰。
>標準のレプリケーションはマスタ/スレーブ方式なので、復旧しない。

なんらかのトラブルでスレーブを使う事になったら、マスタ復旧時にはスレーブをバックアップ>マスタへリストアしてやる必要がある、と。
ここでマルチマスタ方式のmySqlClusterを使うのだろうけど、とりあえずバックアップをとっておきたいの場合はこれでも十分だろう。
(なんといっても設定が簡単だし・・・)

データだけを別システムで流用(リードオンリーで)するような場合は良いっすね。

2009年2月14日土曜日

jQueryを使ってみた

乗るしかない、このビックウェーブに
という事で食わず嫌いだったjQueryを使ってみました。

grailsのwikiでページ一覧をツリーで表示したいというのがあったので、そこを目標に、というかすでにやっつけで作ってコミットしてあります。

本家からjQuery本体をダウンロード
ツリーで調べたらjQueryFileTreeというのがあったのでこれをチョイス。
pluginでjQuery Easing Pluginか、相当するものが必要ということでこれもダウンロード。

pluginってどうするのかなーと思っていたけど、本体をロードした後にロードするだけでいいみたい。

以下まずはjQueryを使って感じた事メモメモ
・prototypeでいう$("elementId")は$("#elementId")で取得
・prototypeでいうForm.serialize()はformエレメントの.serialize()で出来る。
 (formがドキュメント上に1個しかなければ $("form").serialize() でおk)

・ajax処理は以下の感じ


var params=$("form").serialize();
$.ajax({
url:"${createLink(controller:'hoge',action:'foo')}",
type:"post",
data:(params),
success: function(request) {
$('#success').html(request);
}
});


・安全なドキュメントロード後のinit処理
$(document).ready(function() {});

エレメントにイベント追加(クリックを例に)
$("#elementId").click(function(){});

イベントの追加が自然でいい感じ。
extのStoreみたいなのはあるのかなー、あれ凄く好きだったんだけど・・・

ツリーの実装はまた今度

2009年2月12日木曜日

Hudson最強化計画

HudsonをCI以外で使うというブログを読んで強カットインが入った。

そうだよなー、データベースのバックアップをやれば失敗でメールを投げたり、色んなバックアップをまとめて管理しておけるし、バックアップログも残しておけるし、システム稼働監視なんかも出来るじゃまいか。
何よりもそれらが統一されたGUIで行えるわけで、サーバに入り込んでどこで何やってるか把握する必要もなく、Linuxの知識もそれほどいらない。

いやー、こういう使い方は凄く良いと思う!

2009年2月5日木曜日

Grails+BlazeDSでファイルアップロード

FileReferenceを使ったアップロードでは browse() が必須になります。
ファイルを選択してアップする場合は問題ないのですが、決まったファイルのアップロード(別システムから出力されるデータなど)を行う場合には不便です。

なのでBlazeDSでアップロードしてやりましょう。
GrailsでBlazeDSは過去のエントリを参照に。

BlazeDSではActionScriptの byte[] と Java の byte[] をコンバートして通せるようなので、ファイルをbyteにして投げてやります。

private function blazeDsUpload():void {
// ファイルをバイト配列で読み込む
var file:File=new File("/opt/hoge.jpg");
var fs:FileStream=new FileStream();
var bytes:ByteArray=new ByteArray();
fs.open(file, FileMode.READ);
fs.readBytes(bytes, 0, file.size);

//定義してあるRemoteObjectへパラメーターとして渡す
remoteObject.upload({"Filedata":bytes});
}


Grailsのサービス側で受け取るサンプル
byte[]データをファイルへ収めてやります。

def upload(params) {
def fileBytes=params["Filedata"]
def file=new File("/work/hoge.jpg")
file.withOutputStream { out ->
out.write(fileBytes)
}
}

2009年2月4日水曜日

Air+Grailsでファイルアップロードの巻

AirにはFileReferenceというアップロード用のクラスが用意されてますので、そいつを使います。


var fileRef:FileReference=new FileReference();
fileRef.addEventListener(Event.SELECT,selectHandler);
fileRef.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);
fileRef.browse();

// ファイル選択後アップロード処理を実行
private function selectHandler(event:Event):void {
var file:FileReference = FileReference(event.target);
var uploadURL:URLRequest = new URLRequest();
uploadURL.url = "http://localhost:8080/grails/sample/upload";
file.upload(uploadURL);
}

// これがないとエラー画面が出ました
private function ioErrorHandler(event:IOErrorEvent):void {
}


Grails側に受けのアクションを作ってやります。
普通にMultiPartFormDataが来るので、処理してやるだけです。

class SampleController {
def upload={
def file=request.getFile("Filedata")
file.transferTo(new File("/hoge",params["Filename"]))
}
}

2009年2月3日火曜日

grails run-app が永久ループする件について

前にrun-appした時に、起動後永遠とリロードを繰り返して動かないという状況がありました。
その時はinteractiveでrun-appした時はちゃんと動くので、そのままにしてたのですが、最近ふとしたきっかけで解決しました。

groovyファイルとかjavaファイルとかを実行時にコンパイルするのですが、
packageが指定してある場合に、packageと実際にフォルダ位置があっていない場合に上記の症状が発生します。
多分生成するclassと実際のソースパスが一致しないため、いつまでも新規ファイルが投入されたと思ってコンパイルを繰り返すものと思われます。

なんでpackage名とフォルダ構成をあわせてやるだけでOKです。


まったく関係ない話ですがアップルとアドビが組んでiPhone用Flashを開発中という話
ってーことはflexアプリとか動いちゃうんかいなー?アプリ形式に対応すればAppStoreへの登録も可能なわけで :)
もの凄く夢が広がりんぐ!
Androidの方はどうなんだろ、Flashには対応してるみたいだけどアプリ的に扱えるようになればおもしろいですね。
Android/iPhoneのマルチプラットフォームアプリケーション開発とか出来たらかっこいいな〜
adobe labsが出来た辺りからadobeには色々とワクワクさせられます。

2009年1月31日土曜日

Grails-1.1 Beta3の検証

Grails-1.1Beta3がリリースされたのでリリースノートから一部検証・・・

・Persistence of Collections of Basic Types
hasManyでStringとかが指定出来るようになりましたよ。

class Book {
static hasMany = [authors:String]
}


hsqlDBのfileで確認したところ以下のようなテーブルが出来るらしい
CREATE MEMORY TABLE BOOK_AUTHORS(BOOK_ID BIGINT,AUTHORS_STRING VARCHAR(255),CONSTRAINT FKCBA3F8F23FA913A FOREIGN KEY(BOOK_ID) REFERENCES BOOK(ID))
でもscaffoldには対応してくれないみたい。現段階では正直微妙?

・Persistence of Collections of Enum Types
 上のhasManyでEnumが指定できるよ。

enum VehicleStatus { "NONE", "LITTLE", "MANY" }
class Book {
static hasMany=[statuses:VehicleStatus]
}


以下のようなテーブルが出来るっぽい
CREATE MEMORY TABLE BOOK_STATUSES(BOOK_ID BIGINT,VEHICLE_STATUS VARCHAR(255),CONSTRAINT FKA209D4B63FA913A FOREIGN KEY(BOOK_ID) REFERENCES BOOK(ID))
同じくscaffoldには対応してない

・Read-Only Access to Objects
ReadOnlyでデータをひっぱれるよ。

def book = Book.read(1)


通常Grailsではひっぱったドメインはフィールドの値を変更してコントローラーを抜けると、変更された値が自動的に保存されます。
readでひっぱるとフィールドの変更があっても元のデータは更新されません。
んがっ、book.save()したら更新されちゃいました :p
あとfindとかしたい場合はどうするんだろう

・Default Sort Order
ドメインのデフォソートを決められるよ。

class Book {
static hasMany=[authors:Author]
static mapping = {
authors sort:"name"
}

String title
}

class Author {
static belongsTo = [book:Book]
String name
}


今までは book.authors を参照した場合順番はランダムだったのがソートフィールドを指定出来るようになりました。
上の例だとauthorのname順で取得出来ます。
サンプルではドメイン自体のsortも決められるような事がかいてあったけど .list() では確認できませぬでした。 

2009年1月29日木曜日

Flexのちょいネタ

MXMLのclickとかにfunctionを当てる場合の話


<mx:Button click="hoge()" />


と書く所を


<mx:Button click="{hoge()}" />


と中括弧でかこってやると、FlexBuilderがちゃんと関数として解釈してくれるので、CMD+Clickでfunctionまで飛べるお。

俺たちのBirtはこれからだ!

今日はBirtでシコシコと帳票を作っておりますた。

元になるデータを起こすところまではまーまー順調に解消。
さて、このテンプレを元にデータを流すわけですが・・・
今持っているデータだけではさっぱり足りずにフィールドを増やしフォームを増やしとあれやこれやであっという間に時間が。

AirからHTMLをオープン、HTMLからGrailsへアクセスして、Grailsでデータをこねこね、XMLにして返したのをさらにBirtで微調整。
なんかもうエディタがいっぱい開いて目的のソースがどこにあるのかわかりませんよっと。

しかしEclipseのBirtPluginはMacで動かしているせいなのか(?)微妙に動きが悪くてしょんぼりです。
・ラベルで日本語打つ>エンター>消える・・・(ペーストしてエンターだといける)
・データバインディングを変更する>変わらない・・・(セレクタをカーソルで切り替えてエンターだといける)
帳票上のデータが多いと目に見えて重くなるし、ちょっと困ったちゃんです。

それでもフリーでスクリプトやらなんやらバリバリかけてGUIの帳票ツールまであるのは凄い事ですね。

2009年1月27日火曜日

Air(Flex)か〜ら〜のHTMLか〜ら〜のJavascript

AirのHTMLタグから、パッケージに含んだファイル(とかローカルファイルとか)を読み込む方法



var file:File = new File("app:/html/index.html");
var src = new File(file.nativePath).url;
html.location=src;

<mx:HTML id="html" />


パッケージ内にあるJavaScriptは相対パスで読めます。
HTMLとinclude.jsが同じ場所にあるとすれば以下のように。

<script src="include.js"></script>


JavaScriptが全然別のドメインとかでもひっぱてきて使えちゃいますよ。

<script src="http://hoge.jp/outer.js"></script>

なんでJavaScriptのコアをどっかにおいておけばアプリ本体を更新せずにサーバのJSを置き換えて更新も出来ちゃう。

でもってAirからHTMLでロードした中のJavaScriptの実行方法
htmlのcompleteイベントからdomを取得出来るので、、、

private function loadCompleteHandler(e:Event):void {
dom=e.currentTarget.domWindow;
}
<mx:HTML id="html" location="{src}" width="100%" height="100%" complete="loadCompleteHandler(event)" />


domの直下にスクリプトがバインドされているので、それを実行すればオッケィ

html.functionName();

2009年1月23日金曜日

httpBuilderで文字化けする件について

httpBuilderでgoogleのサイトを取得している時はうまくいってたのですがShift_JISのサイトを取り込もうとしたらUTF-8になってしまいました。
まぁよくある事だと思ってソースをさぐっていったのですが、思ったよりも深い所で大変でした、、、

結論からいくとContentTypeが text/html,text/plain,text/xml などの場合は、 ParserRegistry というクラスの parseText という所で、 HttpResponse から charset をあてて InputStream にして返しています。
この charset をあてる所がくせもので、 HttpResponse に含まれるパラメーターの charset を使い、なければ OSデフォ(Charset.defaultCharset().name())をあてるという処理になっています。
おそらくテストしたサイトの response に charset のパラメーターがついていなくて、UTF-8があたったっぽいです。

とりあえず parseText に無理矢理 charset をのせてやったらうまくいきました :)
でもちゃんと作るなら ParserRegistry に charset をあてれるように拡張しないといかんとですね。

2009年1月19日月曜日

httpBuilderが俺にもっと輝けと囁いている

httpBuilderという素敵なものがあったので試してみた

allをダウンロードして、target/dependenciesのjarとhttp-builder自体のjarをlibへコピっと。

Basic認証して、htmlを取得するサンプル。
取得したhtmlはxmlSlurperへ変換し操作しやすいように。


import groovyx.net.http.*
import static groovyx.net.http.Method.*
import static groovyx.net.http.ContentType.*

// basic認証用にbase64したID/Passを作成
def testBytes = "user:pass".getBytes("ISO-8859-1")
def encoded=testBytes.encodeBase64()

def http = new HTTPBuilder("http://hogehoge.jp/requiredBasicAuth")
http.headers=["Authorization":"Basic ${encoded}"]

try {
http.get(contentType:TEXT) { resp, reader ->
def page = new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parseText(reader.text)
def data = page.depthFirst()
data.each { println it }
}
} catch(Exception e) {
println "auth failure"
}


headerの調整とかpost指定とかなしで、簡単にとりたいだけだったら、上のCyberNekoのSlurperを使っている所を使うと簡単

def page = new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parse("http://www.google.co.jp")
def data = page.depthFirst()
data.each { println it }

こんだけでオッケー!

getのオプションで使う query がうまく動かなかったのが気になる所・・・

2009年1月14日水曜日

iPhoneでJsonをごにょごにょ

簡単なJSONを返すアクションを作成

def json = {
def jsonData=[["name":"任天堂","hard":"wii"],
["name":"sony","hard":"PlayStation3"],
["name":"Microsoft","hard":"XBOX360"]]

render(text:jsonData as JSON)
}


ブラウザで確認すると、こんな感じのJSONデータが返ります。

[{"name":"任天堂","hard":"wii"},{"name":"sony","hard":"PlayStation3"},{"name":"Microsoft","hard":"XBOX360"}]


これをiPhoneでうけとってTableViewに表示します。
JSONを取得する部分

- (void)getJSON {
NSURL *jsonURL = [NSURL URLWithString:@"http://localhost:8080/jsonSample/test/json"];
NSMutableString *jsonData = [NSMutableString stringWithContentsOfURL:jsonURL encoding:NSUTF8StringEncoding error:nil];
[jsonData replaceOccurrencesOfString:@"'"
withString:@"\""
options:NSCaseInsensitiveSearch
range:NSMakeRange(0,[jsonData length])];

NSLog(jsonData);

if (jsonData == nil) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Webservice Error" message:@"JSON Dataの取得に失敗しました。" delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
[alert release];
} else {
SBJSON *json = [SBJSON new];
json.humanReadable = YES;

id result = [jsonData JSONValue];
NSLog([json stringWithObject:result error:NULL]);

webResult = [[NSMutableArray alloc] init];

NSEnumerator* enumerator;
enumerator = [result objectEnumerator];

// while文を使って要素にアクセスする
id obj;
while (obj = [enumerator nextObject]) {
[webResult addObject:obj];
}
printf("データ件数 %d",[webResult count]);
}
}


基本は前と一緒です。シングルクォートをダブルクォートに置換したりしてます。
webResultはクラスのフィールドです。
取得した値をループし、webResultへ追加していきます。

InterfaceBuilderでTableViewをおいて、Outletとdelegateを設定します。



dataSource、delegateをFile'sOwnerに設定し、クラスに定義したtableViewと連結します。
クラスにtableView用の定義をします。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [webResult count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
cell = [[UITableViewCell alloc] init];
cell.text = [[webResult objectAtIndex:indexPath.row] objectForKey:@"name"];
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"あなたが選んだのは"
message:[[webResult objectAtIndex:indexPath.row] objectForKey:@"hard"]
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
}


上から順番に
numberOfRowsInSection : テーブルに何件あるかを返すメソッド
cellForRowAtIndexPath : 1行毎に表示するメソッド
didSelectRowAtIndexPath : 行を選択した時のアクション
です。

詳細はメモなんで略 :p

2009年1月12日月曜日

よろしい、ならばiPhoneでJSONだ その3

Grailsのアプリと通信してJSONデータを取得するサンプルです。

Grails側にJSONデータを返すアクションを用意します。

def json = {
def jsonData=["任天堂":"wii","sony":"PlayStation3","Microsoft":"XBOX360"]

render(text:jsonData as JSON,contentType:"application/x-json")
}

contentTypeは application/json でも無指定でも読み込める。

Objective-C側

NSURL *jsonURL = [NSURL URLWithString:@"http://localhost:8080/jsonSample/test/json"];
NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL encoding:NSUTF8StringEncoding error:nil];

if (jsonData == nil) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Webservice Error" message:@"JSON Dataの取得に失敗しました。" delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
[alert release];
} else {
SBJSON *json = [SBJSON new];
json.humanReadable = YES;

id jsonItem = [jsonData JSONValue];
NSLog([json stringWithObject:jsonItem error:NULL]);
}

NSString の initWithContentsOfURL で encoding を指定するのがポイントです。
encodingがあってないと nil になって通信出来てないのかと思って悩んでました・・・

そろそろインターフェース側の処理をやっていこうかな :)

よろしい、ならばiPhoneでJSONだ その2

Objective-CでJsonを取り扱うスニペットめもりんぐ

NSDictionaryとNSStringをいったりきたり


// NSDictionaryからStringに
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
@"The iPhone", @"Today",
@"The World", @"Tomorrow",
nil];
SBJSON *json = [SBJSON new];
json.humanReadable = YES;
NSLog([json stringWithObject:dict error:NULL]);

// StringからNSDictionaryに
NSString *jsonString = @"{\"hoge\":\"foo\",\"wow\":[\"good\",\"cool\"]}";
id jsonObj = [json objectWithString:jsonString error:NULL];
if(jsonObj==NULL || jsonObj==nil) {
printf("NULL dayo\n");
} else {
NSLog([json stringWithObject:jsonObj error:NULL]);
}


jsonでパース出来るのは、ダブルクォートだけです、シングルコートはだめです。(これにずっと気づかなかった・・・)
objectWithStringの返り値はNSArrayだったりNSDictionaryだったりするので、idで受け取る必要があります。

2009年1月6日火曜日

glassfishでメモリチューニングシンドローム

めもめもっと

ドメイン毎に設定ファイルがありやんす。
glassfish/domains/domain1/config/domain.xml

java-configタグ以下に jvm-options タグを書いていく。
デフォは -client とか入ってるのとメモリまったく調整してないのでパツパツ落ちます。

一例

<java-config classpath-suffix="" debug-options="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9009" system-classpath="">
<jvm-options>-server</jvm-options>
<jvm-options>-XX:+UnlockDiagnosticVMOptions</jvm-options>
<jvm-options>-XX:+LogVMOutput</jvm-options>
<jvm-options>-XX:LogFile=${com.sun.aas.instanceRoot}/logs/jvm.log</jvm-options>
<jvm-options>-Djava.endorsed.dirs=${com.sun.aas.installRoot}/lib/endorsed</jvm-options>
<jvm-options>-Djava.security.policy=${com.sun.aas.instanceRoot}/config/server.policy</jvm-options>
<jvm-options>-Djava.security.auth.login.config=${com.sun.aas.instanceRoot}/config/login.conf</jvm-options>
<jvm-options>-Xmx2048m</jvm-options>
<jvm-options>-Xms2048m</jvm-options>
<jvm-options>-Xmn1024m</jvm-options>
<jvm-options>-XX:PermSize=128m</jvm-options>
<jvm-options>-XX:MaxPermSize=128m</jvm-options>
<jvm-options>-XX:NewSize=320m</jvm-options>
<jvm-options>-XX:MaxNewSize=320m</jvm-options>
<jvm-options>-XX:SurvivorRatio=2</jvm-options>
<jvm-options>-XX:TargetSurvivorRatio=70</jvm-options>
<jvm-options>-Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/keystore.jks</jvm-options>
<jvm-options>-Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/config/cacerts.jks</jvm-options>
<jvm-options>-Djava.ext.dirs=${com.sun.aas.javaRoot}/lib/ext${path.separator}${com.sun.aas.javaRoot}/jre/lib/ext${path.separator}${com.sun.aas.instanceRoot}/lib/ext${path.separator}${com.sun.aas.derbyRoot}/lib</jvm-options>
<jvm-options>-Djdbc.drivers=org.apache.derby.jdbc.ClientDriver</jvm-options>
<jvm-options>-Dcom.sun.enterprise.config.config_environment_factory_class=com.sun.enterprise.config.serverbeans.AppserverConfigEnvironmentFactory</jvm-options>
<jvm-options>-XX:NewRatio=2</jvm-options>
<jvm-options>-Dconfluence.disable.peopledirectory.anonymous=true</jvm-options>
</java-config>

よろしい、ならばiPhoneでJSONだ

GoogleCodeにてObjective-CのJSON Frameworkが公開されています。
http://code.google.com/p/json-framework/

これを使ってiPhoneでJSONを使用してみましょう。
以下の記事を参考にしています。
http://iphone.zcentric.com/2008/08/28/using-threads-for-a-json-request/

まずはJSON Frameworkのインストールです。
GoogleCodeからdmgをダウンロードします。
ユーザのLibraryフォルダへSDKsフォルダをコピーします。
(ユーザが hoge だった場合 > /Users/hoge/Library に dmg内の SDKs をコピー)

xcodeを立ち上げて適当な iPhone プロジェクトを生成します。
メニューから、「プロジェクト」>「プロジェクト設定を編集」 で 追加SDK へ以下の設定を追記します。

$HOME/Library/SDKs/JSON/$(PLATFORM_NAME).sdk



「他のリンカフラグ」 へ以下の設定を追記します。

-ObjC -ljson

あとはJSONを使用するコードで JSON/JSON.h をインポートしてやればOKです。

上記サイトにサンプルアプリもアップされています。
以下サンプルアプリを実行した画面です。