ラベル Maven の投稿を表示しています。 すべての投稿を表示
ラベル Maven の投稿を表示しています。 すべての投稿を表示

2009年9月11日金曜日

geronimo-jpa_2.0_spec ?

日本時間9/10夜あたりから、今までずっと使って来た AppEngine + Maven のビルドが急に通らなくなった。

1) org.apache.geronimo.specs:geronimo-jpa_2.0_spec:jar:1.0-EA2-SNAPSHOT

  Try downloading the file manually from the project website.

  Then, install it using the command: 
      mvn install:install-file -DgroupId=org.apache.geronimo.specs -DartifactId=geronimo-jpa_2.0_spec -Dversion=1.0-EA2-SNAPSHOT -Dpackaging=jar -Dfile=/path/to/file

  Alternatively, if you host your own repository you can deploy the file there: 
      mvn deploy:deploy-file -DgroupId=org.apache.geronimo.specs -DartifactId=geronimo-jpa_2.0_spec -Dversion=1.0-EA2-SNAPSHOT -Dpackaging=jar -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]

  Path to dependency: 
   1) org.datanucleus:maven-datanucleus-plugin:maven-plugin:1.1.3
   2) org.datanucleus:datanucleus-jpa:jar:2.0.0-m2
   3) org.apache.geronimo.specs:geronimo-jpa_2.0_spec:jar:1.0-EA2-SNAPSHOT

geronimo-jpa_2.0_specってのがどこのリポジトリにも見当たらない。

pluginの依存を切る

今までpluginの依存をexclusionする方法を知らなかったけど、妙な記述でできたのでメモっておく。maven-datanucleus-pluginで定義されているdatanucleus-jpaへの依存を再定義しているようで気持ち悪い。

<pluginManagement>
  <plugins>
    <plugin>
      <groupId>org.datanucleus</groupId>
      <artifactId>maven-datanucleus-plugin</artifactId>
      <version>1.1.3</version>
      <dependencies>
        <dependency>
          <groupId>org.datanucleus</groupId>
          <artifactId>datanucleus-jpa</artifactId>
          <version>2.0.0-m2</version>
          <exclusions>
            <exclusion>
              <groupId>org.apache.geronimo.specs</groupId>
              <artifactId>geronimo-jpa_2.0_spec</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</pluginManagement>

今回はこれで凌げたけど、そもそもdatanucleus-jpa:2.0.0-m2に依存してしまうという状況が謎。よくよく見てみると、maven-datanucleus-plugin はdatanucleus-jpa二大して[1.1, 1.1.99)というバージョンの範囲(1.1-1.1.98)で指定されている。つまり、2.0.0-m2は範囲外のはずなんだよなぁ。なんでこんな動きをするのかなぁ。maven-datanucleus-pluginじゃなくてdatanucleus-enhancerを使ってみた方が良いのかなぁ。

2009年7月27日月曜日

#appengine 用のmavenプラグインをいくつか1.2.2対応した

以下の二つのエントリで紹介したプラグインを1.2.2対応しました。どちらも、1.2.2-SNAPSHOTというバージョンでdeployしてあります。

gae-maven2-plugin
gae-wicket-quickstart

Wicketの方は、以前のエントリで紹介した、自社で作業しているWikiの内容をいくらか反映したものになっています。詳しくしりたい場合は変更内容の確認をどーぞ。

2009年7月16日木曜日

#appengine for java sdk1.2.2への対応方法

14日の日本時間の午前中にGoogle App Engine BlogにてGoogle App Engine for Java 1.2.2をリリースしたという公式のアナウンスがあった。その日の夜くらいに確認すると、mvnsearchのリポジトリにも1.2.2対応のモジュールがアップロードされているのが確認できたので、動作確認を行っていた。が!!単体テスト周りが結構動かなくて苦労したw やっぱり、mavenとeclipse両方で動作させる事ができなきゃツライんで、そこを目指す人向けにメモを書いておく。

公式のアナウンスより

リリースノートのURLはhttp://code.google.com/p/googleappengine/wiki/SdkForJavaReleaseNotes。目玉としては、pythonのSDKにあるローカル環境でのDatastoreの確認を行う機能が搭載された事。これはありがたい。他にもdatanucleusの不具合対応の取り込みとか。あと、

Better emulate datastore transaction support in the DevAppServer.
ってのがあるので、Low-Level APIでのTransactionがそろそろサポートされたはずだと期待。Task Queue APIは入ってない。

Eclipseのプラグインは、メニューから[Help][Software Updates]で[Software Updatesand Add-ons]画面を開き、[Installed Software]からGoogle関連のモジュールを選択して[Update]すればおk。プロジェクト毎にSDKのバージョンを設定する事も出来るが、設定の[Google][App Engine]でデフォルトをどれにするか?を選択する事も出来る。ついでに書いておくと、Galileo対応のGoogle Plugin for Eclipseは来週くらいにリリースされそうなカンジだ。

sdk単体でのダウンロードURLは http://googleappengine.googlecode.com/files/appengine-java-sdk-1.2.2.zip。日本語のダウンロードサイトは未だに1.2.0へのリンクがあるよぅだw

com.google.apphosting.api.ApiProxy.Environmentのインターフェースが変わっている

public void setDefaultNamespace(String s)が無くなって、Map getAttributes()ってのが増えてる。この件はappengine-java MLでも話題になっていたけど、中の人の返信があって、その内容で落ち着いたみたい。

JDOのEntityの状態が変わった

Query#execute()した直後のEntityの状態
  • 1.2.1: ObjectState.PERSISTENT_NONTRANSACTIONAL_DIRTY
  • 1.2.2: ObjectState.HOLLOW_PERSISTENT_NONTRANSACTIONAL
Transaction開始後に値を操作したEntityの状
    1.2.1: ObjectState.PERSISTENT_NONTRANSACTIONAL_DIRTY
  • 1.2.2: ObjectState.PERSISTENT_DIRTY

変わった、といぅよりは「正しくなった」という事なんでしょね。

低レベルAPIでTransactionがサポートされた

例えば、1.2.1までは次のように無理矢理transaction.rollback()してもロールバックは効かなかったが、1.2.2でよぅやく正しくロールバックされるよぅになっていた。

maven対応は…?

ちゃんとできる。が、ちょっと納得いかない点もある。まずは作業結果のリンクを貼っておく。

自分のJDOの動作確認用プロジェクトではJPAは使っていないんだけど、JPAのモジュールを含めておかないと次のようなExceptionが投げられる。

java.lang.RuntimeException: Unable to replace JPACallbackHandler.
at org.datanucleus.store.appengine.DatastorePluginRegistry.getExtensionPoint(DatastorePluginRegistry.java:66)
at org.datanucleus.plugin.PluginManager.getExtensionPoint(PluginManager.java:65)
at org.datanucleus.plugin.PluginManager.getConfigurationElementForExtension(PluginManager.java:113)
at org.datanucleus.plugin.PluginManager.getAttributeValueForExtension(PluginManager.java:230)
...

で、org.datanucleus:datanucleus-jpa:1.1.4:providedを追加する。maven的にはコレでokだけど、この状態で$ mvn eclipse:eclipseしてしまうと、eclipse側でテストを実行した時に次のようなExceptionが投げられる(根っこの原因を抜粋)。

org.datanucleus.exceptions.NucleusException: Plugin (Bundle) "org.datanucleus.jpa" is already registered. Ensure you dont have multiple JAR versions of the same plugin in the classpath. The URL "file:/dropins.ganymede/google/plugins/com.google.appengine.eclipse.sdkbundle_1.2.2.v200907131030/appengine-java-sdk-1.2.2/lib/user/orm/datanucleus-jpa-1.1.4.jar" is already registered, and you are trying to register an identical plugin located at URL "file:/Users/shin1/.m2/repository/org/datanucleus/datanucleus-jpa/1.1.4/datanucleus-jpa-1.1.4.jar."

これを回避する為に、pom.xmlのmaven-eclipse-pluginの定義で、configuration/excludes/excludeの値に org.datanucleus:datanucleus-jpaを追加してやるとおk。

mavenから実行する時のエンハンサとして使用するmaven-datanucleus-pluginのバージョンが1.1.3しか見つからなかったので1.1.3を使っていて、とりあえずそれでも問題は起こっていない。が、他のモジュールに合わせて1.1.4がリリースされるんじゃないかな。

2009-07-27追記

UnitTest中にUserServiceを使いたい場合は、TestEnvironment.javaのgetAuthDomain(), isLoggedIn(), getEmail()が値を返す必要があるので注意〜。

2009年7月5日日曜日

197X第2回 LT大会に参加した #197X

appengine/java用の開発環境を簡単に作れるよ!というLTを行ったが、デモの最後のmaven integration-testの実行中のappengine-java-sdkのzipファイルのダウンロードに時間がかかりすぎてしまって、その間にドラ!となっちゃったw 質疑応答中に完了していたっぽいので、20秒ほど足りなかったよぅだ。

皆のLT

やっぱ197XメンバのLTはどれも面白い。そんな中でLT大賞をあげたい!と思ったのが kousyou さんの暗渠ネタ。"暗渠"という単語は初めて聞いたけど、buzzってたし、今後大流行間違い無し!

ありがとう

参加された皆様、会場を提供してくださったグリー株式会社様、会場の温度調整をがんばったいちいくん、「作る」「営む」に励んでおられるござ先輩、2日後くらいに筋肉痛が来るはずでお気の毒ですなyamashiroさん、ドラで多数の心臓を止めかけたドラ娘、みんなありがとうございました!

あと、Jiemamyメンバがいつも下品なワケじゃないよ!普段はちゃんとマジメな話してますから!

2009年6月19日金曜日

GAE/JのDevAppServerMainを起動するmaven pluginを作った

2009-07-27追記

SDKのバージョンに合わせてバージョンが変わってますので更新のエントリも参照する事!

今までmaven archetype pluginをいくつか作って来たけど、どれも「Eclipseが前提」となっていて、せっかくarchetype:generateでプロジェクトが作れるし、単体テストもできるのに結局Google Plugin for Eclipseかappengine-java-sdkも必要なんだよな〜、mavenを使った開発っぽくないよな〜、というカンジがあった。

mavenを使うんだから、sdkなんていちいち落としてくるなんておかしいよ、プラグインが勝手に解決しろや〜、て思うもんね。そこで、以下のようなMavenプラグインを作った。

  • com.google.appengine.tools.KickStartを使ってcom.google.appengine.tools.development.DevAppServerMainを起動する。
  • 試験のためのプラットフォームとしてSDK本体が必要になるが、公式のダウンロードサイトからダウンロードしてくる事が可能。ダウンロードしてきた場合は例えばtarget/sdkなどに展開し、そこをSDKのルートとして使用する。

つまり、jettyプラグインとかcargoプラグインみたいにselenium等でintegration-testを自動で行ったり、さくっとアプリを起動して動作確認するためのモジュールです。

使い方

pluginRepositoryとしてhttp://gae-j-samples.sourceforge.jp/maven/repositoryを追加し、com.shin1ogawa:gae-maven2-plugin:1.2.1-SNAPSHOT:start(つまり、groupId=com.shin1ogawa, artifactId=gae-maven2-plugin, version=1.2.1-SNAPSHOT, goal=start)を実行してください。stopゴールはパラメータは無しで、startゴールのパラメータは以下の通り。

address(localhost),disableUpdateCheck(true),port(8080),server
これらはDevAppServerMainにそのまま渡すパラメタです。それぞれカッコ内の値がデフォルトの値です。server、って何に使うんだっけ…?
javaHome
javaを起動するためのホームディレクトリです。省略した場合はSystem.getProperty("java.home")の値を使用します。
warDirectory
SDKが使用するアプリケーションのディレクトリです。デフォルトの値はwarが設定されています。この直下にWEB-INFが配置されている必要があります。
sdkRootDirectory
appengine-java-sdkがインストールされたディレクトリを指定しますが、sdkUnZipDirectoryが指定されているとそっちを優先します。
sdkZipFile
SDKのZipファイルの場所。デフォルトの値はhttp://googleappengine.googlecode.com/files/appengine-java-sdk-1.2.1.zipが設定されています。
sdkUnZipDirectory
SDKのZipファイルを展開するディレクトリ。
sdkSaveAs
もしsdkZipFileパラメータがhttpだったりしてローカルじゃない場合に、保存するファイル名。デフォルトの値はappengine-java-sdk-1.2.1.zipが設定されています。sdkUnZipDirectoryで指定したディレクトリ配下に作成されます。もし既に存在していた場合は、リモートからダウンロードしません。
wait
DevAppServerMainを起動した状態で、そのプロセスが終了するのを待ちます。mavenでintegration-testを実行する際はpre-integration-testフェーズでfalseを指定してstartゴールを実行し、post-integration-testフェーズでstopゴールを実行して停止する必要があります。ちなみに、falseで起動してしまうと、プロセスがふたつ(KickStartと、そこから起動されたDevAppServerMain)起動されて、maven実行後にもこのふたつは止まらずに残ってしまいます。この場合は手動でkillする必要があります。

とりあえず細かい事は気にせず、以下の例を見るのが手っ取り早いです。一度でも使用するとローカルリポジトリに入ってくるので、$ mvn help:describe -Dplugin=com.shin1ogawa:gae-maven2-plugin:1.2.1-SNAPSHOT -Ddetailすると説明が表示されるはずです。

例

例えば、以下のようにpom.xmlでintegration-test用のprofileを定義して、$ mvn -P integration-test installのようなカンジでprofileを指定しつつintegration-testフェーズが実行されるようなゴールを実行する。すると以下のように動作する。

  1. 通常のsurefire-testはskipされる。
  2. で、integration-testフェーズの直前にgae-maven2-plugin:startが実行される。
    1. 公式サイトからSDKがダウンロードされる
    2. SDKがtarget/sdkに展開される
    3. そのSDKを利用してKickStart経由でDevAppServerMainを起動する
  3. integration-testフェーズでは**/servlet/*Test.javaにマッチするテストケースが実行される。
  4. integration-testが終了すると、gae-maven2-plugin:stopが実行され、DevAppServerMainも終了する。
ちなみに、ゴールにintegration-testを指定すると、post-integration-testフェーズが実行されない。この挙動は初めて知った!!モチロン、stopゴールも実行されない為、KickStart,DevAppServerMainのふたつのプロセスが残ってしまう。

また、このプラグインを動作確認する程度だけれども、WebDriverを使ったintegration-testを行うサンプルを以下のプロジェクトに追加しています。

  • http://sourceforge.jp/projects/gae-j-samples/svn/view/gae-jdo-simple-sample/?root=gae-j-samples

2009年6月14日日曜日

GAE/J+T2(+Guice)用のarchetypeプラグインを作成した

昨日のWicket+GAE用のarchetypeプラグインに続けて、t2-framework(+guice Adapter)をGAE/J上で動作させるプロジェクトを作るarchetypeプラグインも作成した。本日S2Conでt2の話を聞いてわくわくしたし。

使い方

maven2がインストールされてパスも通った状態で、以下のコマンドを実行してください。

mvn archetype:generate -DarchetypeGroupId=com.shin1ogawa -DarchetypeArtifactId=gae-t2-guice-quickstart -DarchetypeVersion=1.0-SNAPSHOT -DarchetypeRepository=http://gae-j-samples.sourceforge.jp/maven/repository -Dostype=mac

もちろん、途中で改行してはイケマセン。archetype:createではなくarchetype:generateです。ただWicketの時とは違い、間違えてcreateしてもarchetype:createは失敗するのですぐ気づくと思います。

ostypeというパラメータを設定していますが、macの時だけ指定してください。windowsとlinuxはJava6の時にJava Buildpathにどういう値を設定すれば良いのかわからずまだ作っていないのですが、もしJava6が設定できなかった場合はEclipseに取り込み後にDataNucleusがEclipse内でエンハンスに失敗するとか、Classのバージョンが云々というエラーが見れるはずです。その場合はプロジェクトの設定で「JavaBuildPath」で使用されるJDKのバージョンをJava6に設定してやれば大丈夫です。。。が、明日にでもLinuxとWindowsで試す事にします。

プロジェクトが生成できたら、生成されたプロジェクトフォルダに移動して以下のコマンド。

$ mvn eclipse:eclipse dependency:copy-dependencies

後はEclipseに取り込めばOKOKです。もちろんEclipse上、Maven上、双方で単体テストが可能です。

他にも細かい説明は昨日のエントリや、下に示すドキュメントを参照してください。

公開してる場所

リポジトリ
http://gae-j-samples.sourceforge.jp/gae-t2-guice-quickstart/source-repository.html
プロジェクトの説明
http://gae-j-samples.sourceforge.jp/gae-t2-guice-quickstart/ja/

2009年6月13日土曜日

GAE/J+Wicket用のarchetypeプラグインを作成した

2009-07-27追記

SDKのバージョンに合わせてバージョンが変わってますので更新のエントリも参照する事!

久々にWicketを触っていると、"やっぱJava屋にはWicketが一番気持ちいいな…"となったので、前回のものに加えてWicket+GAE用のquickstartも作った。

使い方

maven2がインストールされてパスも通った状態で、以下のコマンドを実行してください。

$ mvn archetype:generate -DarchetypeGroupId=com.shin1ogawa -DarchetypeArtifactId=gae-wicket-quickstart -DarchetypeVersion=1.0-SNAPSHOT -DarchetypeRepository=http://gae-j-samples.sourceforge.jp/maven/repository

改行を入れてはイケマセン。それと、archetype:createではなくarchetype:generateですので注意。うっかりcreateゴールを使うと、テンプレートのhtmlが思わぬ場所にコピーされてしまいます。

プロジェクトが生成できたら、生成されたプロジェクトフォルダに移動して以下のコマンドを。

$ mvn eclipse:eclipse dependency:copy-dependencies

詳しい説明は以前のエントリを見てください。eclipseのGAESDKプラグインを1.2.0のままの人とかも要注意。

公開してる場所

リポジトリ
http://gae-j-samples.sourceforge.jp/gae-wicket-quickstart/source-repository.html
プロジェクトの説明
http://gae-j-samples.sourceforge.jp/gae-wicket-quickstart/ja/

archetype:generateうぜぇ

色々聞いてくんな、一発で作らせろという人はgenerateゴール実行時に、以下のようにgroupId, artifactId, versionを渡してinteractiveMode=falseする事でサクッとプロジェクトができあがります。

mvn archetype:generate -DarchetypeGroupId=com.shin1ogawa -DarchetypeArtifactId=gae-wicket-quickstart -DarchetypeVersion=1.0-SNAPSHOT -DarchetypeRepository=http://gae-j-samples.sourceforge.jp/maven/repository -DgroupId=com.hoge -DartifactId=com.hoge.gae-wicket -Dversion=1 -DinteractiveMode=false

2009年5月19日火曜日

antlr3-maven-plugin

ANTLRWorksが便利なんだけど、grammarファイルが大きいのか、ソースのジェネレートがうまく動作してくれない。

error(10): internal error: org.antlr.tool.Grammar.createLookaheadDFA(Grammar.java:1242): could not even do k=1 for decision XXX; reason timed out(>1000ms)

上記のようなメッセージがいくつか出て、cpuをひとつ使い切ったまま処理が返ってこなくなってしまい、強制終了するしかなくなる(少なくとも分単位では落ち着いてくれない)。$ java -cp antlr-3.1.3.jar ...とやってもいいんだけど、せっかくだからmavenでできないか?と思ったら、mavenのプラグインも提供されていた。知らなかった。

antlr3-maven-plugin

grammarファイルは"src/main/antlr3"配下に配置するのがお約束のようだ。ただし、src/main/antlr3直下に置くとマズイようで、適当なフォルダ(Lexer,Parserが出力されるべきパッケージ構成を作成する)に配置するのが良いみたい。

Mavenでは問題無くソースがジェネレートできているので、ANTLRWorksは編集用にしか使っていないカンジ。

2009年5月16日土曜日

GAE/J用のarchetypeプラグインを作成した

やっぱ依存関係とかはmavenを使わないと面倒だ。依存ライブラリのソースの添付とかも簡単にできるし。そんなワケでなんとかmavenとeclipseを共存させられないか、と四苦八苦していたのだがよぅやくなんとかなったっぽい。といぅわけでarchetypeプラグインを作ってみた。

使い方

まずはmaven的にプロジェクトを作成する
artifactを作成するフォルダに移動して以下のコマンドを実行する。
$ mvn archetype:create -DarchetypeGroupId=com.shin1ogawa -DarchetypeArtifactId=gae-jdo-quickstart -DarchetypeVersion=1.0-SNAPSHOT -DremoteRepositories=http://gae-j-samples.sourceforge.jp/maven/repository -DgroupId=com.yourdomain -DartifactId=yourArtifactId
強調斜体で表記した部分は適宜変更してください。必要であれば作成するartifactのversionやらpackageを追加で指定すればいいと思う。
テストケースだけ実行してみる?
作成したartifactのフォルダに移動して以下のコマンドを実行する。
$ mvn clean test
mavenからのテストケースも実行できるはず。
eclipse用に構成する
作成したartifactのフォルダに移動して以下のコマンドを実行する。
$ mvn eclipse:eclipse dependency:copy-dependencies
依存モジュールをコピーしているのは、eclipseからGAE SDKでwebアプリとして起動する時に必要なjarを/war/WEB-INF/libにコピーする必要があるからです。
eclipseに取り込もう
eclipseを起動して、[Import][Existing Projects...]で作成したartifactのフォルダを選択するだけ。
注意!eclipseの設定で、"M2_REPO"がローカルリポジトリをさしている必要がありまっす。これはeclipseの設定画面を開いて、[Java][Build path][Classpath variables]で追加できます。[Name]に"M2_REPO"、[Path]に例えば"/Users/shin1/.m2/repository"みたいなかんじ。普段からmavenとeclipseを使っている人なら設定済みじゃないかと。
Webアプリを実行する
これはeclipseからしか実行できません。プロジェクト直下の"launches/gaej.web.launch"を右クリックして、"Run As"から実行してください。
eclipseのコンソールに”The server is running at http://localhost:8080/”と表示されたら正常に起動できてます。ブラウザからhttp://localhost:8080/にリクエストしてみると、簡単なゲストブックが動作するはず。
eclipseからテストケースを実行してみる
プロジェクト直下の"launches/gaej.unittest.launch"を右クリックして、"Run As"から実行してください。

作成される雛形について

  • プラグイン名を見てもわかるとおり、jdoを使う雛形が作成されます。
  • Viewには素のjspを使ってます。
  • memcacheを少し使ってます。
  • mavenからunit testを実行できるので、CIするのも簡単です。
  • eclipseからunit testを実行できるので、リズムよく開発できます。

何か問題があれば、TwitterなりFriendFeedなりで連絡をくださいー。

追記

以下が前提です!

  • mavenがインストールされている。
  • EclipseにGoogle App Engine SDK Pluginがインストールされていて、1.2.1にアップデート済みである。

mavenはいいとして、eclipse pluginについて初期の1.2.0を入れてしまっている人は以下の手順でUpdateする事ができます。

  1. [Help][Software Updates]メニューを開く
  2. [Google Update Site for Eclipse 3.4]にチェックを入れる。
  3. [Install]ボタンを押す。
  4. 終わるまで待つ。再起動を促されたら素直に再起動する。
  5. Eclipseの設定画面を開いて[Google][App Engine]を開くと、"1.2.0"と"1.2.1"があるので、"1.2.1"をチェックする(デフォルトにする)。

このあたりのGoogleAppEnginePluginのバージョンやらPluginを導入するタイミングによっては、以下のようなExceptionが出ます。

java.lang.NullPointerException
 at com.yourdomain.logic.AbstractLogic.newQuery(AbstractLogic.java:29)
...
Caused by: org.datanucleus.exceptions.NucleusException: Plugin (Bundle) "org.datanucleus.store.appengine" is already registered. Ensure you dont have multiple JAR versions of the same plugin in the classpath. The URL "file:/Users/shin1/Documents/projects.gae/yourArtifactId/war/WEB-INF/lib/datanucleus-appengine-1.0.1.jar" is already registered, and you are trying to register an identical plugin located at URL "file:/Users/shin1/Documents/projects.gae/yourArtifactId/war/WEB-INF/lib/datanucleus-appengine-1.0.1.final.jar."

この場合はプロジェクトを作り直すか、war/WEB-INF/lib/datanucleus-appengine-1.0.1.final.jarを消してやってください(プロジェクトを作り直した方が無難)。

2009年5月15日金曜日

mvnsearch上のGAE/J関連の1.2.0から1.2.1への移行での変更

先のエントリでmvnsearchリポジトリも1.2.1への対応が云々書いたけど、なんかartifactIdがビミョーに見覚えあったり無かったりで「あれ?」てカンジだった。なのでよく確認してみると、結構な差があった。gae-mvn-archetypeプロジェクトの/trunk/gae-mvn-archetype/src/main/resources/archetype-resources/pom.xmlのr33での変更内容を見るとよくわかるようだ。

ただしこのpom.xmlだとmaven-datanucleus-pluginの設定がされてないから、エンハンスもmavenでやるとすると以下のようになる。

mvnsearchのGAE/J関連モジュールも1.2.1が追加されてる

Google App Engine for Java SDKの1.2.1がリリースされたけど、mvnsearchのリポジトリも追随されたようです。

  • http://mvnsearch.org/maven2/com/google/appengine/appengine-api-1.0-sdk/
  • http://mvnsearch.org/maven2/com/google/appengine/appengine-api-1.0-stubs/
  • http://mvnsearch.org/maven2/com/google/appengine/appengine-tools-sdk/
  • http://mvnsearch.org/maven2/com/google/appengine/appengine-api-1.0-runtime/

pomのテンプレートもまた書き直さなきゃなぁ。

追記

よく見るとartifactIdが1.2.0の頃と随分違う。詳しくは次のエントリで補足した。

2009年5月11日月曜日

GAE for Java用のサンプルプロジェクトを公開しておきます

シンプルな構成

GAE for Javaでテンプレートとして使えるサンプルを作っていたが、おおよそできた。

  • ORMにはJDOを使う
  • EclipseでのJDOエンハンス対象クラスを設定する
  • Eclipse、MavenのどちらからもJDO関連のモジュールの単体テストが動作する
  • Javaのロガーのフォーマッタを入れ替える(1ログ1行で表示する)
  • Presentation層にはjspとjstlを使う

主にMavenでの単体テストが可能な事がメインで、これができるとHudsonでMavenプロジェクトを定義してのCIが可能となるので必須の機能なはず。みんなCIしてるもんね?CIを想定しなくて許されるのは小学生までだよね?
極力シンプルにしたので、ここから色々派生する事ができると思う。

こいつはシンプルなのでarchetype-pluginを作ってもいいんだけど、要望はなさげ。というのも、$ mvn eclipse:eclipseしてもEclipse側でうまく扱えない→結局ローカルでの実行にantかeclipseが必要になるので、maven単体でIntegrationTestが実行できそーにない。ここまでできればmaven一本で環境構築できて嬉しいんだけどな。cargo-pluginを使ってtomcatにデプロイして動作させる事もできるのかもしれんけど、gaeのsdkとの振る舞いの違いが気になって何かイヤだ。
ちなみにeclipseとmavenをうまく連動する事ができない問題は、eclipse側でmavenでいう依存性のスコープの概念が無いという問題と、jdoのdatanucleusのエンハンスの問題。GoogleAppEnginePlug-inによるエンハンス実行時の環境でのシステムプロパティを触る事ができれば結構うまく連動できそうなんだけども、GoogleAppEnginePlug-inのソースが見当たらないのでなんともならない。

  • https://svn.sourceforge.jp/svnroot/gae-j-samples/gae-jdo-simple-sample/trunk/gae-jdo-simple-sample

t2-frameworkの構成

t2-frameworkを使ったエントリも書いていたが、そちらのサンプルは主に以下のようにしている。

  • ORMにはJDOを使う。
  • EclipseでのJDOエンハンス対象クラスを設定する
  • Eclipse、MavenのどちらからもJDO関連のモジュールの単体テストが動作する
  • Javaのロガーのフォーマッタを入れ替える(1ログ1行で表示する)
  • Presentation層には何も使っていない。jQueryからt2-frameworkの@Ajaxなインターフェースを呼び出して描画してるだけ
  • t2はGuiceアダプタを使用している

t2-frameworkはシンプルさのバランスが絶妙なので、上記のシンプルなサンプルがあればt2はすぐ動作するし、サンプルなんて必要無いくらい。Viewに何のフレームワークも使っていないのは、はt2の@AjaxでWebAPIドリブンぽくGAE/Jを使い、WebブラウザでのViewにはjQueryで描画するだけにしておきたいため。
自分が作るサービスではWebのインターフェースはおまけ程度にして、AIRを正式なクライアント側プラットフォームとして使おうと考えている。なので、shotたん、new AMF()したいです…とかつぶやいておく事にする。

  • https://svn.sourceforge.jp/svnroot/gae-j-samples/gae-jdo-simple-sample/trunk/gae-jdo-simple-sample

Wicketの構成

Wicket on GAE/Jについての最後のエントリ以降、何も触ってませんw

t2のトコでも書いた通り、自分はWebでのインターフェース自体を重視していないためWicketにはあんまりこだわっていない。テンプレートとPageクラスの両方でコンポーネントの構造を意識する必要がある時点でDRYじゃないなーとかマイナスな思考も強くなって来た。Javaからのアプローチをする時はPageクラスさえ構築すれば後はよしなにやってくれろや、とか。
とはいえWicketは大好きなんで、ちょっとしたサービスをGAE/Jにデプロイする際はWicketを使う可能性が一番高いと思う。シンプルなサンプルを作成するためにjstlとか触ったら、htmlに式を書くとかありえなく思えて気絶しそうになったし。

2009年5月4日月曜日

MavenからGAE/Jの単体テスト

最低限のpomを記載しておく。ポイントは”datanucleus-appengine"と"datanucleus-core"のscopeをruntimeにしておく事。こいつらがビルド時に取り込まれてしまうとmaven-datanucleus-pluginでのエンハンス中にエラー停止してしまう。

先のエントリで書いた単体試験の内容で、$ mvn clean testしてテストが通る事を確認できるはずだ。

<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.shin1ogawa</groupId>
  <artifactId>gae-jdo-simple-sample</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>GAE JDO Simple Sample</name>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
    <dependency>
      <groupId>javax.persistence</groupId>
      <artifactId>persistence-api</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>javax.jdo</groupId>
      <artifactId>jdo2-api</artifactId>
      <version>2.3-SNAPSHOT</version>
    </dependency>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.4</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-library</artifactId>
      <version>1.1</version>
      <scope>test</scope>
    </dependency>
    <!-- GAE for java(compile) -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api</artifactId>
      <version>1.0-sdk-1.2.0</version>
    </dependency>
    <!-- GAE for java(test) -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-api-stubs</artifactId>
      <version>1.0</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>appengine-local-runtime</artifactId>
      <version>1.0</version>
      <scope>test</scope>
    </dependency>
    <!-- GAE for java(runtime) -->
    <dependency>
      <groupId>com.google.appengine</groupId>
      <artifactId>datanucleus-appengine</artifactId>
      <version>1.0.0.final</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.datanucleus</groupId>
      <artifactId>datanucleus-core</artifactId>
      <version>1.1.0</version>
      <scope>runtime</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <plugin>
        <!-- http://www.datanucleus.org/products/accessplatform/enhancer.html#maven2 -->
        <groupId>org.datanucleus</groupId>
        <artifactId>maven-datanucleus-plugin</artifactId>
        <version>1.1.0</version>
        <configuration>
          <verbose>true</verbose>
          <mappingIncludes>**/entity/*.class</mappingIncludes>
          <fork>true</fork>
          <enhancerName>ASM</enhancerName>
          <api>JDO</api>
        </configuration>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>enhance</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>**/TestEnvironment.java</exclude>
            <exclude>**/Abstract*.java</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <repositories>
    <repository>
      <id>DataNucleus</id>
      <url>http://www.datanucleus.org/downloads/maven2</url>
    </repository>
    <repository>
      <id>mvnsearch</id>
      <url>http://www.mvnsearch.org/maven2</url>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>DataNucleus</id>
      <url>http://www.datanucleus.org/downloads/maven2</url>
    </pluginRepository>
  </pluginRepositories>
</project>

これでHudsonのMavenプロジェクトでのCIも可能になりますね!

2009年4月20日月曜日

GAE for Javaをarchetype:createする

Google Codeにmaven2のgae-maven-archetypeというarchetyoe plug-inプロジェクトがあり、それが使える。自分はt-2+Guice+JPA用のものを作って使っているが、gae-maven-archetypeプロジェクトのものが汎用的で使いやすそう。

  • $ mvn archetype:create -DgroupId=com.shin1ogawa -DartifactId=com.shin1ogawa.gae.sample -DarchetypeArtifactId=appengine-quickstart -DarchetypeGroupId=org.mvnsearch.maven.archetypes -DarchetypeVersion=1.0.1 -DremoteRepositories=http://www.mvnsearch.org/maven2

上記のコマンドを使えばプロジェクトが作成できて(斜体部分の2カ所は適宜修正が必要)、公式のEclipse Plug-inなしでもすぐに開発を始める事ができる。ただし、antと併用する形になり、「$ mvn package」でビルド、「$ ant runserver」で実行、「$ ant update」でデプロイできる。

というか、モジュールが「http://www.mvnsearch.org/maven2/com/google/appengine/」というリポジトリに配置されているので、これを使って独自にmaven2との連携をしていく事もできる。

追記

antを実行する際は、appengine_homeパラメータを設定してやる必要がある。例えば「$ ant runserver -Dappengine_home=/opt/appengine-java-sdk-1.2.0/」みたいなカンジ。

2009年4月9日木曜日

GAE/Javaでt2-frameworkを使ってみる

Wicketを試す合間にT2(with Guice+JPA)を試していたのでその手順を。

開発環境の準備

Eclipseを使用している事と、EclipseにGAE用のプラグインをインストールしてある事。

プロジェクトを作ってT2用に設定する

Eclipse上でプロジェクトを作る
新規作成Wizardで[Goolge/Web Application Project]を選択する。なお、JDKは1.6に変更しておく事!
T2関連のモジュールをコピーする
t2-frameworkのサイトから「Core/T2-${version}-ga」と「Core/Lucy-${version}-ga」をダウンロードする。また、今回はついでにGuiceも使いたいので「Samples/T2 + Guice + JPA sample application」もダウンロードしておく。以下をダウンロードしたモジュールから抜き出して${baseDir}/war/WEB-INF/libにコピーして、[Build path][Add to Build Path]しておく。他にはcommons-langも適当に拾って来て同様に配置、ビルドパスに含めておこう。
  • commons-0.5.1-ga.jar
  • guice-1.0.jar
  • guice-servlet-1.0.jar
  • guiceadapter-0.5.1-ga.jar
  • logback-classic-0.9.15.jar
  • logback-core-0.9.15.jar
  • slf4j-api-1.5.6.jar
  • t2-0.5.1-ga.jar

各種設定ファイルの準備をする

web.xmlを修正する
対象ファイルはwar/WEB-INF/web.xml。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
  <context-param>
    <param-name>t2.encoding</param-name>
    <param-value>UTF-8</param-value>
  </context-param>

  <filter>
    <filter-name>Guice Servlet Filter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
  </filter>
  <filter>
    <filter-name>t2</filter-name>
    <filter-class>org.t2framework.t2.filter.T2Filter</filter-class>
    <init-param>
      <param-name>t2.rootpackage</param-name>
      <param-value>com.shin1ogawa.page</param-value>
    </init-param>
    <init-param>
      <param-name>t2.container.adapter</param-name>
      <param-value>org.t2framework.t2.adapter.GuiceAdapter</param-value>
    </init-param>
    <!--
    <init-param>
      <param-name>t2.eagerload</param-name>
      <param-value>true</param-value>
    </init-param>
    -->
    <init-param>
      <param-name>t2.exclude-resources</param-name>
      <param-value>css, js</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>Guice Servlet Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>  
  <filter-mapping>
    <filter-name>t2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>
log4.propertiesを修正する
src/log4j.propertiesに以下を追記しておく。
log4j.category.DataNucleus.Connection=DEBUG, A1
log4j.category.DataNucleus.Query=DEBUG, A1
log4j.logger.org.t2framework=TRACE, A1
log4j.logger.com.shin1ogawa=TRACE, A1
最後の行は自分のアプリに合わせて適宜変更する事。
セッションを有効にする
GAEの設定ファイルである、war/WEB-INF/appengine-web.xml内のappengine-web-app要素の直下に以下を追加する。
<sessions-enabled>true</sessions-enabled>
persistence.xmlを作成する。

src/META-INFにpersistence.xmlを作成する。内容は以下のとおりで、これはGAE/JavaでJPAを使う時に必要なもの。JDOを使わずJPAを使うのであればGAEプラグインがデフォルトでsrc/META-INF直下に作成するjdoconfig.xmlは削除してもかまわない、と思う。

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

  <persistence-unit name="transactions-optional">
    <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
    <class>com.shin1ogawa.entity.Messages</class>
    <properties>
      <property name="datanucleus.NontransactionalRead" value="true"/>
      <property name="datanucleus.NontransactionalWrite" value="true"/>
      <property name="datanucleus.ConnectionURL" value="appengine"/>
    </properties>
  </persistence-unit>
</persistence>
class要素に記述するのはJPAのEntityクラスなので、自分のアプリに合わせて適宜修正する事。
T2に読ませるServiceProviderの設定ファイルを作成する
src/META-INFにservicesフォルダを作成し、com.google.inject.Moduleというファイルを作成する。内容は以下の一行で、自分のアプリに合わせて適宜修正する事。
com.shin1ogawa.ApplicationModule

Javaのクラスを作成する

JPA用のModule
package com.shin1ogawa;
import javax.persistence.*;
import com.google.inject.*;
public class JpaModule extends AbstractModule {
  @Override protected void configure() {
    bind(EntityManager.class).toProvider(new Provider() {
      public EntityManager get() {
        EntityManager manager = Persistence.createEntityManagerFactory(
            "transactions-optional").createEntityManager();
        manager.setFlushMode(FlushModeType.COMMIT);
        return manager;
      }
    }).in(Singleton.class);
  }
}
JPA用のEntity
今回は超単純なEntityをひとつだけ用意してみる。persistence.xmlのclass要素でJPA的に使えるように登録する必要がある(上記手順で設定済み)。
package com.shin1ogawa.entity;
import java.util.Date;
import javax.persistence.*;
@Entity
public class Messages {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
  private String userName;
  private String message;
  private Date updated;
  public Long getId() { return id; }
  public void setId(Long id) { this.id = id; }
  public String getUserName() { return userName; }
  public void setUserName(String userName) { this.userName = userName; }
  public String getMessage() { return message; }
  public void setMessage(String message) { this.message = message; }
  public void setUpdated(Date updated) { this.updated = updated; }
  public Date getUpdated() { return updated; }
}
処理モジュールを作成する
Guiceを使って管理する対象にしたいので、インターフェースと実装クラスを分離している。
package com.shin1ogawa.logic;

import java.util.List;
import com.google.appengine.api.users.User;
import com.shin1ogawa.entity.Messages;

public interface IMessagesLogic {
  public Messages newMessage(User user, String messageBody);
  public List<Messages> selectAll();
}
package com.shin1ogawa.logic;

import java.util.*;
import javax.persistence.*;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.*;
import com.google.appengine.api.users.User;
import com.google.inject.Inject;
import com.shin1ogawa.entity.Messages;

public class MessagesLogic implements IMessagesLogic {
  static final Logger logger = LoggerFactory.getLogger(MessagesLogic.class);

  @Inject EntityManager em;

  public Messages newMessage(User user, String messageBody) {
    Messages message = new Messages();
    message.setUserName(user != null ? user.getNickname() : "unknown");
    message.setMessage(messageBody);
    message.setUpdated(new Date(System.currentTimeMillis()));

    EntityTransaction transaction = em.getTransaction();
    transaction.begin();
    em.persist(message);
    transaction.commit();
    return message;
  }

  public List<Messages> selectAll() {
    @SuppressWarnings("unchecked")
    List resultList = em.createQuery(
        "Select m from com.shin1ogawa.entity.Messages m").getResultList();
    return resultList;
  }

  @Override public String toString() {
    return ToStringBuilder.reflectionToString(this);
  }
}
実装クラス中のJPQLでクラス名をFQCNで指定ている。"Select m from Messages m"とか短いクラス名で記述したいのだけど、そうするとORMの実装であるDataNucleusがクラス名を解決できないというエラーを出してくる。oem.xmlを作ってやってもダメ。なのでとりあえずFQCNで記述しておいた。誰か解決方法がわかる人は教えてください!
T2のアプリケーション用のModule
package com.shin1ogawa;
import org.slf4j.*;
import com.google.inject.*;
import com.shin1ogawa.logic.IMessagesLogic;
import com.shin1ogawa.logic.MessagesLogic;
public class ApplicationModule extends AbstractModule {
  @Override protected void configure() {
    install(new ServletModule());
    install(new JpaModule());
    bind(IMessagesLogic.class).to(MessagesLogic.class).in(Scopes.SINGLETON);
  }
}
T2のページクラス
ちなみに、jspは好きではないのでjspは使ってない。データの投稿もGetで行う事が前提で書いた。データの一覧表示用とデータの投稿用のページクラス。
package com.shin1ogawa.page;

import java.util.*;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.t2framework.t2.annotation.core.Default;
import org.t2framework.t2.annotation.core.Page;
import org.t2framework.t2.contexts.WebContext;
import org.t2framework.t2.navigation.SimpleText;
import org.t2framework.t2.spi.Navigation;

import com.google.inject.Inject;
import com.google.inject.servlet.RequestParameters;
import com.google.inject.servlet.RequestScoped;
import com.shin1ogawa.entity.Messages;
import com.shin1ogawa.logic.IMessagesLogic;

@RequestScoped
@Page("messageList")
public class MessageList {
  @Inject @RequestParameters Map params;

  @Inject IMessagesLogic logic;
  
  @Default public Navigation index(WebContext context) {
    StringBuilder b = new StringBuilder();
    b.append(ToStringBuilder.reflectionToString(this));
    
    List<Messages> messageList = logic.selectAll();
    if (messageList != null) {
      b.append("messages count=").append(messageList.size()).append("\n");
      for (Messages messages : messageList) {
        b.append(ToStringBuilder.reflectionToString(messages)).append("\n");
      }
    } else {
      b.append("messages count=0").append("\n");
    }
    return new SimpleText(b.toString());
  }
}
package com.shin1ogawa.page;

import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.t2framework.t2.annotation.core.Default;
import org.t2framework.t2.annotation.core.Page;
import org.t2framework.t2.contexts.WebContext;
import org.t2framework.t2.navigation.Redirect;
import org.t2framework.t2.navigation.SimpleText;
import org.t2framework.t2.spi.Navigation;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.inject.Inject;
import com.google.inject.servlet.RequestParameters;
import com.google.inject.servlet.RequestScoped;
import com.shin1ogawa.logic.IMessagesLogic;

@RequestScoped
@Page("addMessage")
public class AddMessage {
  @Inject @RequestParameters Map params;

  @Inject IMessagesLogic logic;

  @Default public Navigation index(WebContext context) {
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();

    final String message = params.get("message") != null ? params.get("message")[0] : null;
    if (StringUtils.isEmpty(message)) {
      return new SimpleText("メッセージが入力されていません。");
    } else {
      logic.newMessage(user, message);
      return new Redirect(MessageList.class);
    }
  }
}
表示がめっちゃくちゃ適当だけど、自分はWebのUIをメインに使う気がない(だからこそT2っていう選択肢でもある)のでこんなもんで十分なのだ。

アプリケーションを実行する

GAEプラグインでプロジェクトを作った場合は、プロジェクトと同時にWeb Applicationの実行の構成も作られているのでそれを実行し、「http://localhost:8080/messageList」を開けばおk!最初は空っぽだが、「http://localhost:8080/addMessage?message=hoge」とかやるとデータが増えていくはずだ。データはアプリケーションを終了しても消えない模様。

2009年3月18日水曜日

mavenで複数のWebコンテナを使ってintegration-testする

profile機能をうまく使う。project/profiles配下の要素で、必要なだけprofileを用意するカンジ。mvn clean installするとintegration-testが実行される。

projects直下のbuild/pluginsで定義しているsurefire-test
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <includes>
      <include>**/server/**/*Test.java</include>
    </includes>
  </configuration>
  <executions>
    <execution>
      <id>surefire-integration-test</id>
      <phase>integration-test</phase>
      <goals>
        <goal>test</goal>
      </goals>
      <configuration>
        <skip>false</skip>
        <includes>
          <include>**/client/**/*Test.java</include>
        </includes>
      </configuration>
    </execution>
  </executions>
</plugin>
testフェーズでは**/server/**をtest対象とし、integration-testフェーズでは**/client/**をtest対象としている。
開発時用のprofile
<profile>
  <id>development</id>
  <activation>
    <activeByDefault>true</activeByDefault>
  </activation>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <includes>
            <include>**/server/**/*Test.java</include>
          </includes>
        </configuration>
        <executions>
          <execution>
            <id>surefire-integration-test</id>
            <phase>integration-test</phase>
            <configuration>
              <skip>true</skip>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</profile>
  • integration-testフェーズでは何もしない。
  • リソースファイルはデフォルトのsrc/main/resources,src/test/resourcesが適用される。
jetty上でintegration-testをするprofile
<profile>
  <id>it-on-jetty</id>
  <build>
    <resources>
      <resource>
        <directory>src/it/resources</directory>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.1.10</version>
        <configuration>
          <contextPath>webappSample</contextPath>
          <scanIntervalSeconds>10</scanIntervalSeconds>
          <stopKey>foo</stopKey>
          <stopPort>9999</stopPort>
          <connectors>
            <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
              <port>8080</port>
              <maxIdleTime>60000</maxIdleTime>
            </connector>
          </connectors>
        </configuration>
        <executions>
          <execution>
            <id>start-container</id>
            <phase>pre-integration-test</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <scanIntervalSeconds>0</scanIntervalSeconds>
              <daemon>true</daemon>
            </configuration>
          </execution>
          <execution>
            <id>stop-container</id>
            <phase>post-integration-test</phase>
            <goals>
              <goal>stop</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <skip>true</skip>
        </configuration>
      </plugin>
    </plugins>
  </build>
</profile>
  • integeration-test前後でjettyの起動と終了を行う
  • 通常のtestフェーズではsurefire-testは実行しない。
  • リソースファイルはsrc/it/resource配下が適用される
tomvat上でintegration-testをするprofile
<profile>
  <id>it-on-tomcat</id>
  <build>
    <resources>
      <resource>
        <directory>src/it/resources</directory>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.codehaus.cargo</groupId>
        <artifactId>cargo-maven2-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <configuration>
          <container>
            <containerId>tomcat5x</containerId>
            <zipUrlInstaller>
              <url>http://archive.apache.org/dist/tomcat/tomcat-5/v5.5.27/bin/apache-tomcat-5.5.27.zip</url>
            </zipUrlInstaller>
            <output>${project.build.directory}/tomcat5x.log</output>
            <log>${project.build.directory}/cargo.log</log>
            <timeout>60000</timeout>
          </container>
          <configuration>
            <home>${project.build.directory}/tomcat55</home>
            <properties>
              <cargo.servlet.port>8080</cargo.servlet.port>
              <cargo.logging>high</cargo.logging>
            </properties>
          </configuration>
          <deployer>
            <deployables>
              <deployable>
                <groupId>com.shin1ogawa</groupId>
                <artifactId>webappSample</artifactId>
                <type>war</type>
                <properties>
                  <context>webappSample</context>
                </properties>
                <pingURL>http://localhost:8080/webappSample/</pingURL>
              </deployable>
            </deployables>
          </deployer>
        </configuration>
        <executions>
          <execution>
            <id>start-container</id>
            <phase>pre-integration-test</phase>
            <goals>
              <goal>start</goal>
              <goal>deployer-deploy</goal>
            </goals>
            <configuration>
              <wait>false</wait>
            </configuration>
          </execution>
          <execution>
            <id>stop-container</id>
            <phase>post-integrastion-test</phase>
            <goals>
              <goal>stop</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <skip>true</skip>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <pluginRepositories>
    <pluginRepository>
      <id>cargo m2 release repository</id>
      <url>http://cargo.codehaus.org/dist2</url>
      <releases>
        <enabled>true</enabled>
      </releases>
    </pluginRepository>
  </pluginRepositories>
</profile>
  • integeration-test前後で、tomcatのダウンロード&インストール&起動&デプロイと、終了を行う
  • testフェーズではsurefire-testは実行しない。
  • リソースファイルはsrc/it/resource配下が適用される
製品用のパッケージングをするためのprofile
<profile>
  <id>production</id>
  <properties>
    <maven.test.skip>true</maven.test.skip>
  </properties>
  <build>
    <resources>
      <resource>
        <directory>src/production/resources</directory>
      </resource>
    </resources>
  </build>
</profile>
  • testもintegration-testも行わない。
  • リソースファイルはsrc/production/resources配下が適用される。

実はprofile機能は、プロパティの設定等を切り替える程度にしか使えていなかったんだけど、pluginの設定とかも書けるって最近知ったw profile機能のおかげでかなーーり幅が広がった。Hudson等のCIツールとの相性も非常に良いと思う。

で、ここまでは定義方法のテンプレートなんだけど、integration-testでの問題点として、自分は以下のような問題に直面している。例えばクライアント側Seleniumとかならいいんだけど、そうじゃなくてSwingなどのリッチクライアントだった時。当然、クライアント側のモジュールのカバレッジを取りたいワケだ。だがしかし、coberturaプラグインはtestフェーズで実行する時にしかカバレッジ計測が働かないようなのだ。testフェーズよりも前のフェーズで無理矢理Webサーバを起動するようにすればできない事はないのだけれど、キレイじゃないんだよなぁ。それとも、自前のlifecycleを定義してしまぅか…。

2009年2月25日水曜日

ビルド結果のファイルを別のマシンへ転送する(maven, Hudson)

maven+hudsonを使ってビルドやら何やらを自動化しているが、成果物を別のマシンにscpしたいという要求が出てきた。これをHudson+plug-inでやるか、maven2+plug-inでやるか?で迷った。といぅか、どっちも目的の処理を行う事ができるplug-inがあるのか?からして謎だったw maven2はwagonを使った経験が遠い過去にあったので、それかなー?くらいに目星はついたが、Hudsonは一度設定してしまえばそぅそぅ触る事も無いしすっかり忘れかけていたり。

maven

ずばり、maven-wagon-pluginで正解だった。

  • deploy-pluginで別マシンへinstallする時と同じように、settings.xmlのservers要素の配下に転送先のserverの設定が必要。
    <server>
      <id>remotehost</id>
      <username>shin1ogawa</username>
      <password>password</password>
    </server>
  • pom.xmlはbuild/plugins配下に以下のように設定。この例ではpackageフェーズが実行されたタイミングで起動している。
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>wagon-maven-plugin</artifactId>
      <version>1.0-beta-1</version>
      <executions>
        <execution>
          <id>upload-jar</id>
          <phase>package</phase>
          <goals>
            <goal>upload</goal>
          </goals>
          <configuration>
            <serverId>remotehost</serverId>
            <url>scp://192.168.1.109/</url>
            <fromDir>target</fromDir>
            <includes>**/*.jar</includes>
            <excludes>*-sources.jar</excludes>
            <toDir>/home/shin1ogawa/tmp</toDir>
          </configuration>
        </execution>
      </executions>
    </plugin>
    

Hudson

電車の中でiPhoneからぶつぶつつぶやいていたら、@kompiroからアドバイスが。

名前もそのもまんま。設定方法もシンプル。

  1. 上記リンクからプラグインファイル(*.hpi)をダウンロードして、Hudsonのルート画面から[Manage Hudson][Manage Plugins]をたどってプラグインをインストールしておく。んで再起動する。
  2. Hudsonのルート画面から[Manage Hudson][Configure System]をたどり、[SCP repository hosts]を設定する。例ではパスワードで認証する設定だけど、鍵ファイルを使う事もできそぅだ(項目があるし。これでできなかったらビックリする。)。
  3. ファイル転送を行うためのjobの設定画面を開き、[Post-build Actions]に表示されている[Publish artifacts to SCP Repository]にチェックを入れる。すると他のプラグインと同じように、プラグインの設定パネルが表示されるのであれこれ設定する。[Destination]にはHudsonの全体設定の[SCP repository hosts][Root Repository Path]で設定したパスからの相対パスを指定する。存在しないフォルダを指定してみると、ちゃんとフォルダを作ってから転送してくれた。

転送先が複数ある場合であれば、hudson+SCP-pluginだと複数のjobにしなきゃならん?ような気がするので、maven-wagon-pluginの方がいいかな。maven-wagon-pluginであればexecutionの定義をたくさん書いてしまえばいいだけだし。

2009年2月6日金曜日

FlexSDKのソースを少し覗いてみる

ActionScript3の構文解析をやりたい(正確には構文解析されたオブジェクトを利用したい)と思っているので、しげるんがアドバイスしてくれたASCを触ってみている。とりあえずはWikiにも書かずメモ程度にここに書いておく。

準備

EclipseにSubversiveとq4eを入れてある事が前提。プラグイン等の詳細はwikiの方を参照する。ちなみに、FlexSDKのソースはJava5以上が前提です。

ソースの取得

FlexSDKのリポジトリのURLは"http://opensource.adobe.com/svn/opensource/flex/sdk"。

  1. 構文解析を行ってくれるモジュールは"modules/asc"なのでcheckoutすりゃいいのだが、FlexSDKのサイトを見ると最新の安定板のバージョンは3.2系っぽいので、tagにある"3.2.0.3958"からcheckoutする事にする。
  2. ついでに、swfを扱えそうなモジュールである"modules/swfutils"も"tags/3.2.0.3958"からcheckoutする。
  3. checkoutしただけだと、Eclipse上ではそもそもJavaProjectですらない扱いとなってしまうが、次の手順でq4eを使って簡単にビルドする。

ビルド

q4eを前提に、pom.xmlを書いた。

  1. まず以下のpom.xmlをascプロジェクトのルートフォルダに配置し、パッケージエクスプローラ上でプロジェクトのルートを右クリックし、[Maven2][Use Maven dependency management]を選択する。
    <?xml version="1.0" encoding="UTF-8"?>
    <project>
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.adobe.opensource</groupId>
      <artifactId>asc</artifactId>
      <name>asc</name>
      <version>3.2.0.3958</version>
      <url>http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/modules/asc</url>
      <build>
        <sourceDirectory>src/java</sourceDirectory>
        <outputDirectory>target/classes</outputDirectory>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>1.5</source>
              <target>1.5</target>
              <encoding>UTF-8</encoding>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    ちなみにGroupId,ArtifactID,Versionについては正式なものがわからんので適当にそれっぽく書いた。mavenを使わない開発なんてしたくないし、開発中はこれで十分だと思う。実際に何か作って依存するなら、SDK本体に付属のasc.jarを使えば良い。
  2. これだけで、q4eが勝手にJavaProjectとしてEclipseに認識させてくれた上にコンパイルも終了している(target/classesに出力されている)。
  3. 実際触るには、ソースも欲しいので、パッケージエクスプローラから[Maven2][Execute Goal]を選択して、Goalには"clean source:jar install"を指定する。これを実行すれば、target直下に"asc-3.2.0.3958.jar","asc-3.2.0.3958-sources.jar"がパッケージとして出力される。q4eを使えばこんなにラクチン。
ascだけが必要ならこれだけで良いのだが、swfutilsも気になるのでこっちもビルドする。swfutilsは以下のpom.xmlを使って、ascと同じ手順を実施すればそれだけでOKOK。
<?xml version="1.0" encoding="UTF-8"?>
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.adobe.opensource</groupId>
  <artifactId>swfutils</artifactId>
  <name>swfutils</name>
  <version>3.2.0.3958</version>
  <url>http://opensource.adobe.com/svn/opensource/flex/sdk/trunk/modules/swfutils</url>
  <build>
    <sourceDirectory>src/java</sourceDirectory>
    <outputDirectory>target/classes</outputDirectory>
    <testSourceDirectory>test/java</testSourceDirectory>
    <testOutputDirectory>target/test-classes</testOutputDirectory>
    <resources>
      <resource>
        <directory>abc</directory>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.5</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.xmlgraphics</groupId>
      <artifactId>batik-svggen</artifactId>
      <version>1.7</version>
    </dependency>
    <dependency>
      <groupId>com.adobe.opensource</groupId>
      <artifactId>asc</artifactId>
      <version>3.2.0.3958</version>
      <type>jar</type>
    </dependency>
  </dependencies>
</project>

使ってみる

とりあえず適当なActionScript3のソースを作成して、解析させてみる。

  1. 適当に自分のプロジェクトを作成して、先にビルドしたascのモジュールかプロジェクトに依存させる。モジュールを依存させる場合はモチロン、ソースの添付もお忘れなく。
  2. Eclipseで実行の構成を作成する。メインクラスは"macromedia.asc.embedding.ScriptCompiler"で、引数として"-d -AS3 -outdir target -import ../asc/abc/toplevel.abc -import ../asc/abc/builtin.abc Hoge.as"を指定する。ここで「../asc/abc/*.abc」を指定しているが、これはascプロジェクト配下にあるabcファイルの事。これでコンパイルが実行され、targetフォルダにコンパイルされたabcが配置される。

構文解析に関するソースを読む

自分の場合は構文解析された結果を利用したいだけなワケだが、これすら大変。ascのソースには以下の特徴がある。

  • 基本的にコメントは一切ない。
  • かなり汚い。バッドプラクティスとしてとても参考になるケースがしばしば。
  • toString()がひどい。クラス名をリテラルで埋め込んであるだけとか。仕方がないからtoString()の中を置き換えてやれ、と思ってやってみると、「toString()の結果をロジックとして利用している箇所がある」ため、メインのロジックに影響を与えてしまい、正常動作しなくなる。
  • 構文ツリーのルートとなるNodeクラス(クラスだよ、インターフェースじゃないよ!)にあった「public static final boolean useDebugToStrings = false;」なる便利そうなフラグを発見して「そりゃデバッグモードがいいだろ」とフラグをtrueにすると、動作しなくなる。おそらくデバッグモードで動作確認されていないのではなかろうか。
とにかくむかつく事が多い。checkstyle使えよfindbugs使えよ!せっかく便利なツールが揃ってるのにさ!

まぁ、そう言ってても進まないので、ソースを読んでみたい人は以下をエントリポイントに読み進めていくのが良いと感じた。

  • ScriptCompiler/BatchCompiler
    これは実際にコンパイルを行う箇所なので、構文ツリーをどのように意味ある状態でアクセスできるように構築していけば良いかの参考になる。だが、常に同じ要素数を持つべき複数のListがそのまま生でフィールドとして扱われているとか、ヒドイので注意が必要。このクラス内でPairというクラスが定義されており、そいつらが前述の「ヒドイList」のインデックスに対応して各Fileの間の参照関係やら何やらを保持している、という事も重要。インデクスで管理て…Compilerではそんなに長期間保持する必要も無いからやっつけ仕事的な組まれ方なのかもしれない。
  • ProgramNode
    ASやabcのファイルと同じ単位でできあがるNode。この中にクラスに対応するNodeが複数ぶらさがって行くカンジ。
  • 普通はDOMを見るときはルートのインターフェースを見るだろ?とか思うかもしれないが、それはおすすめしない。Nodeはダメ。このクラスはコードリーディングの役に立たない(DOMのNodeのサブクラスのソースがいかにヒドイ事になっていそうか、という苦労の覚悟を決めるには役立つ)。
  • ObjectListというListのラッパークラスもあり、Nodeのコンテナとして使用される事が多い。が、何のためにラッパーになっているのか想像できない仕様。
  • 後はObjectValueやらReferenceValue等のValueObjectみたいなヤツら。
肝心の「参照の解決」などはNodeの中に存在しているというより(存在しているが)、上記のScriptCompiler等の中で定義されているいくつかのListで管理されている点に注意が必要。

…まぁ、地味に読んでいくしかないです。

2008年7月28日月曜日

mavenで各種Reportを生成するpom.xmlのTemplate その2

以前書いたエントリ「maven2.0.7で各種Reportを生成するpom.xmlのTemplate」のメンテナンス。以前のエントリでは、以下の問題がある事が判明した!参考にしてしまった人、ごめんなさい><
  • surefire-report:reportのからみで、testが二回実行されてしまう
  • target/site/cobertura/coverage.xmlが出力されないため、Hudsonのcobertura pluginからxmlを拾えない
テンプレートと書きつつ、実際はそれをメンテしつつ使っているから、エントリもメンテすべきだったのです。mavenについては、Wikiの方で更新をしていく事にします。このブログの情報を参考にされる方は、エントリと合わせてwikiも参照してください。

testが2回走ってしまう件

//reporting/plugins/pluginでsurefire-reportを設定するときに以下のよぅに設定します。
<!-- surefire-report: http://maven.apache.org/plugins/maven-surefire-report-plugin/ -->
<plugin>
  <artifactId>maven-surefire-report-plugin</artifactId>
  <reportSets>
    <reportSet>
      <reports>
        <report>report-only</report>
      </reports>
    </reportSet>
  </reportSets>
</plugin>
reportSetとか、そんなの知らなかったヨ!ちなみに、testフェーズだけ実行したときもsurefire-reportを走らせたければ、//build/plugins/pluginでsurefire-report pluginを以下のように設定すると、testを二回走らせずにreport出力ができますた。
<plugin>
  <artifactId>maven-surefire-report-plugin</artifactId>
  <executions>
    <execution>
      <phase>test</phase>
      <goals>
        <goal>report-only</goal>
      </goals>
    </execution>
  </executions>
</plugin>

target/site/cobertura/coverage.xmlが出力されない件

こちらは簡単。といぅか、前回のエントリに含まれていない方がどぅかしてた。//reporting/plugins/pluginでcoberturaの設定をする際に、configurationの子要素としてformats/formatを使って「xml」の出力を設定する必要があります。デフォルトではhtmlだけが出力されます。
<!-- cobertura: http://mojo.codehaus.org/cobertura-maven-plugin/ -->
<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>cobertura-maven-plugin</artifactId>
  <configuration>
    <formats>
      <format>xml</format>
      <format>html</format>
    </formats>
  </configuration>
</plugin>

まとめ

2点の問題の修正を反映し、各pluginの不要な設定を極力はずしたものがコチラ。plugin間のversionの問題は相変わらずシビアっぽいので、例えばfindbugsの結果レポートがdashboardに乗ってこない、等の症状は出ますが、それはとりあえず無視してます。
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.shin1o</groupId>
  <artifactId>com.shin1o.reportsample</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0-SNAPSHOT</version>
  <name>com.shin1o.reportsample</name>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.4</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- http://maven.apache.org/plugins/maven-compiler-plugin/ -->
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <encoding>UTF-8</encoding>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <!-- surefire: http://maven.apache.org/plugins/maven-surefire-plugin/ -->
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <systemProperties>
            <property>
              <name>net.sourceforge.cobertura.datafile</name>
              <value>${basedir}/target/cobertura/cobertura.ser</value>
            </property>
          </systemProperties>
          <!-- スラッシュ区切り、javaを指定。
          <excludes>
            <exclude>com/shin1o/exclude/**/*.java</exclude>
          </excludes>
          -->
        </configuration>
      </plugin>
      <!-- surefire-report: http://maven.apache.org/plugins/maven-surefire-report-plugin/ -->
      <!-- testフェーズでもsurefire-reportが必要なら有効にする。
      <plugin>
        <artifactId>maven-surefire-report-plugin</artifactId>
        <executions>
          <execution>
            <phase>test</phase>
            <goals>
              <goal>report-only</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      -->
    </plugins>
  </build>

  <reporting>
    <plugins>
      <!-- cobertura: http://mojo.codehaus.org/cobertura-maven-plugin/ -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>cobertura-maven-plugin</artifactId>
        <configuration>
          <formats>
            <format>xml</format>
            <format>html</format>
          </formats>
          <instrumentation>
            <!-- ignoreはパッケージ名で指定。
            <ignores>
              <ignore>com.shin1o.exclude.*</ignore>
            </ignores>
            -->
            <!-- includes/excludesはスラッシュ区切り,classを指定
            <includes>
              <include>com/shin1o/include/**/*.class</include>
            </includes>
            <excludes>
              <exclude>**/*Test*.class</exclude>
            </excludes>
            -->
          </instrumentation>
        </configuration>
      </plugin>
      <!-- surefire-report: http://maven.apache.org/plugins/maven-surefire-report-plugin/ -->
      <plugin>
        <artifactId>maven-surefire-report-plugin</artifactId>
        <reportSets>
          <reportSet>
            <reports>
              <report>report-only</report>
            </reports>
          </reportSet>
        </reportSets>
      </plugin>
      <!-- jxr: http://maven.apache.org/plugins/maven-jxr-plugin/ -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jxr-plugin</artifactId>
        <configuration>
          <inputEncoding>UTF-8</inputEncoding>
          <outputEncoding>UTF-8</outputEncoding>
        </configuration>
      </plugin>
      <!-- jdepend: http://mojo.codehaus.org/jdepend-maven-plugin/ -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jdepend-maven-plugin</artifactId>
      </plugin>
      <!-- pmd/cpd: http://maven.apache.org/plugins/maven-pmd-plugin/ -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-pmd-plugin</artifactId>
        <configuration>
          <linkXref>true</linkXref>
          <sourceEncoding>UTF-8</sourceEncoding>
          <minimumTokens>100</minimumTokens>
          <targetJdk>1.5</targetJdk>
        </configuration>
      </plugin>
      <!-- findbugs http://mojo.codehaus.org/findbugs-maven-plugin/ -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>findbugs-maven-plugin</artifactId>
        <configuration>
          <xmlOutput>true</xmlOutput>
          <effort>Max</effort>
        </configuration>
      </plugin>
      <!-- dashboard: http://maven.apache.org/plugins/dashboard-maven-plugin/ -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>dashboard-maven-plugin</artifactId>
      </plugin>
      <!-- site: http://maven.apache.org/plugins/maven-site-plugin/ -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-site-plugin</artifactId>
        <configuration>
          <inputEncoding>UTF-8</inputEncoding>
          <outputEncoding>UTF-8</outputEncoding>
        </configuration>
      </plugin>
      <!-- project-info: http://maven.apache.org/plugins/maven-project-info-reports-plugin/ -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-project-info-reports-plugin</artifactId>
      </plugin>
    </plugins>
  </reporting>

  <repositories>
    <repository>
      <id>Maven Snapshots</id>
      <url>http://snapshots.maven.codehaus.org/maven2/</url>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <releases>
        <enabled>false</enabled>
      </releases>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>Codehaus Snapshots</id>
      <url>http://snapshots.repository.codehaus.org/</url>
    </pluginRepository>
  </pluginRepositories>
</project>

2008年4月6日日曜日

liftを動作させてみる

scalaで構築されたWebFrameworkであるliftを動作させてみよぅか、と。
svnからソースを取得する。
$ svn checkout http://liftweb.googlecode.com/svn/trunk/ liftweb
mavenでbuild、installする。
$ cd liftweb/liftweb
$ mvn install -Dmaven.test.failure.ignore=true
sampleアプリを起動する。
$ cd sites/example
$ mvn jetty:run
[INFO] Started Jetty Server
という出力を確認できたら、http://localhost:8080/をブラウザで開く。

「Welcome to the lift Web Framework」とか書かれたPageが表示される。いくつかのSampleが含まれたProjectだったみたいだ。いくつかSampleがあるので色々試してみよう。ただ、CometのSampleは動作しないっぽい。

途中でmavenのtest失敗を無視するように設定しているのは、「Lift WebKit」がtestに失敗するため。trunkを使ったのがマズイんだろぅと思う。tags/0.7っていうtagがあるよぅなので、そっちを使う方がいいのかもしれない。気になる人は以下の手順でtestreportをhtmlで出力すれば確認できる。確認できるんだけど、自分は意味がわからなかったw

  • $ cd liftweb/liftweb/lift
  • $ mvn surefire-report:report -Dmaven.test.skip=true
  • file:///Users/shin1/tmp/20080406/liftweb/liftweb/lift/target/site/surefire-report.html
    をブラウザで開く("/Users/shin1/tmp/20080406"は適宜読み替えて)。