DBUnit@Oracle DB時のAmbiguousTableNameException

これまたオールドスクールなツールを使っていて問題発生。
DBUnitを使って単体テストを実施していた時なのだけど、下記の例外に遭遇。

org.dbunit.database.AmbiguousTableNameException: AQ$_SCHEDULES
 at org.dbunit.database.DatabaseDataSet.initialize(DatabaseDataSet.java:140)
 at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:186)
 at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:98)
 at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:67)

どうやらOracleを使っていて違うschemaに同じtable名が存在するとこうなっていて、
この時はコネクション生成するときにschemaを指定すべしとのこと。

This exception is thrown by IDataSet when multiple tables having the same name are accessible. This usually occurs when the database connection have access to multiple schemas containing identical table names.
Possible solutions:
1) Use a database connection credential that has access to only one database schema.
2) Specify a schema name to the DatabaseConnection or DatabaseDataSourceConnection constructor.
3) Enable the qualified table name support (see How-to documentation).

Another common reason for this exception to be thrown is when an XML file contains the same table multiple times whereas a different table is between the definition of the duplicate table.

2の案ね。

どうでも良いけどDBUnit.orgの本家サイトがドメイン切れて税理士紹介サイトに取られてる

checkboxにチェックしていないことを送信

久しぶりにクライミング以外の話題。

まぁ当たり前なのだけど、HTMLのcheckboxでformを送信するとき、checkが入っていないとサーバーに値自体送信されない。
このため、例えばサーバー側で情報をセッション領域などに入れて持ちまわす場合、
一旦チェックを入れた状態を保持してしまうと、それを外すことが画面からの操作ではできなくなってしまう。
その問題の解決には、Springではcheckboxと一緒にhidden項目を作って、それを一緒に送信するのがセオリーみたい。

<input type="checkbox" value="true" name="springCheckboxTest" id="springCheckboxTest">
<input type="hidden" value="on" name="_springCheckboxTest">

こんな感じでcheckboxのnameの先頭にアンスコつけたnameのhidden項目を送信すると、
勝手にspring側でバインドしてくれるみたい。

そして、上記のようなhtmlはspringのformタグを使えば出力可能とのこと。

<form:checkbox path="springCheckboxTest" />

参考:13.9.4. The checkbox tag

なるほどね!

Servlet3.0の@WebFilterの微妙な点

ボルダリングじゃなくて久々に本業系のエントリ!でもボルダラーって結構IT系の人が多いので意外と通じる?
#関係ないけどセッションってIT界隈でもボルダリング界隈でもある単語ですよね!

今年は新入社員のインストラクターになったので、色々とエンプラ系Javaのイロハを教育中なのだけども。その中でServletでいろいろ作って勉強しましょうということで。。久々に演習問題を作っていると、Tomcatは最新ではバージョンは7になっていて、Servlet3.0に追いついて、その目玉機能として、EoDとして「Annotation based configuration」が新しく定義されている。アノテーションを利用することでServletの開発が簡単になるという。いいね!自分が大分世の中から周回遅れにされていることがわかってショックだったけど、さっそく使ってみよう!

例えば、Servletの実行時間を測定するFilterで下記のようなものを作ってみるとか。

その後、FilterをChainさせて奥のほう(Servlet側)で例外をスローさせて下記のようなスタックトレースを眺めさせてChainの構造を考察&理解させようと思っていたのだけど、、、。

8 04, 2014 7:26:52 午後 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: サーブレット org.sasaki.Problem2 のServlet.service()が例外を投げました
java.lang.RuntimeException
at org.defenceless.filter.MeasuringTimeFilter.doFilter(MeasuringTimeFilter.java:47)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.defenceless.filter.ExceptionFilter.doFilter(ExceptionFilter.java:40)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.defenceless.filter.AnotherFilter.doFilter(AnotherFilter.java:40)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
(略)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:314)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:724)

ん、、アノテーションのAPIとして順番を指定するような仕様がない。。色々と調べてみると、下記の記事発見。

How to define Servlet filter order of execution using annotations

う~む。。。結局、Filterの刺さる順序をアノテーションでは指定できない。結局Web.xmlに書くしかない。。順番指摘できないFilter誰が使うのだろうか!?

JJUG CCC 2013 SpringとBouldering Day 3の日

最近土日開催になって、個人的には参加しやすくなったJJUG(ジェイジャグ)に参加して来た。今回はJava EE 7とか、ScaleなどのJVM言語などのリリース話、まぁ後はコズミネクサスがどんだけスゴいかっていう宣伝スポンサー様の講演などなど。相変わらず狭義のJavaにとどまらない多種多様なセッションがあって非常にためになった。

個人的には、直近のプロジェクトでは、開発標準化支援や、もっと低級なところだとAPI設計・ネーミングルール策定とかをワシワシやっているので、山本裕介(@yusuke)の下記の発表が本当に勉強になった。Twitter4Jのような広く一般的に拡散していくライブラリのAPI設計方針と、MUT行程でPGが100人を超すくらいの規模のSIでの共通部品設計方針って、結構似たところがあるなあと思った。

  • 性悪説に基づく
    • そのAPIに基づく全ての開発者が高いレベルを有しているわけではない
    • 開発者はJavaDocなどを確認せずにメソッド名から機能を推察して利用する
    • コピペ開発
  • 拡散したものに手を加えて修正することは大変
  • すぐにはupdateしてもらえない
  • etc…

みたいな。そのような時にしっかり回すために大切なのは、わかりやすい(利用しやすい)API設計と、「No GGRKS(ノーググレカス)」ポリシーなのだねえ。非常に勉強になりました。発表資料もアップされていたので、あとでまた見返してみよう。

特に印象に残ったのは、下記のくだり。
例えば、Twitter側が「ユーザ情報」と、フォロワー数などの付加的な情報を「ユーザ詳細情報」みたいに分けて提供していたので、JavaのAPIのVersion1.0としても下記のように提供していました、と。

Version1.0

Class User{}
Class UserWithStatus extends User{
    getFriendsCount();
    getFollowersCount();
}

ところがTwitter側が提供するAPI仕様が変って、フォロワー数などの情報も「ユーザ詳細情報」ではなく「ユーザ情報」に含めるようになりました、と。こういうデカい仕様変更を、どうやってライブラリ側で緩衝していくか(利用者側に対して隠すか)というと、いきなり削除するのではなくて、いったんメソッドを非推奨にして、「利用は出来るんだけどもIDE上では警告が出る」ようにしますと。

Version1.04

Class User{
    getFriendsCount();
    getFollowersCount();
}
/** @deprecated */
Class UserWithStatus extends User{
}

そしてメジャーバージョンが上がるような大きな更新の時にバッサリ削除すると。

Version2.0

Class User{
    getFriendsCount();
    getFollowersCount();
}

こうすると利用者側からも比較的変更が緩やかになるね、と。確かに。部品側のAPIを変えるのは利用者(SIだとアプリチームとか)からも苦情がくるし、億劫になりがちなんだけども、だからと言ってイビツな設計のまま時が経ってアプリが育っても、傷口が広がるだけだもんねぇ。こういうところはライブラリ管理方針とかリリース方針(○○な変更はメジャーバージョンアップあげますよ、とかの決めごと)などと合わせてプロジェクト内で整備していくと、利用者(アプリ)側も準備ができるし、事故が防げそうなので、実践していこう!勉強になりました!

JJUGを見終わったら、アベ君から電話で

「今日どっかで壁登りましょうよ〜〜。」

と電話があったので、2日連続になっちゃうけど、二つ返事でOKして、恵比寿J&Sへ。今日は先日残してた7級を平らげて終了!

あべ君は6級を倒して、5級は苦戦してて宿題になってた。こちらも勉強になりました!

maven2でJavaEE5のマルチモジュールプロジェクトひな形作成

やっぱmavenすごいってことで、めも。予め下記をダウンロードする。

[shell]
# それぞれinstallする
$ mvn install:install-file -Dfile=ee5-archetype-war-jsf-1.1.jar -DgroupId=sample.plugin -DartifactId=ee5-archetype-war-jsf -Dversion=1.1 -Dpackaging=maven-plugin
$ mvn install:install-file -Dfile=ee5-archetype-ejb-1.1.jar -DgroupId=sample.plugin -DartifactId=ee5-archetype-ejb -Dversion=1.1 -Dpackaging=maven-plugin
$ mvn install:install-file -Dfile=ee5-archetype-ear-1.1.jar -DgroupId=sample.plugin -DartifactId=ee5-archetype-ear -Dversion=1.1 -Dpackaging=maven-plugin

#top levelのprojectを作成
$ mvn archetype:create -DarchetypeArtifactId=maven-archetype-site-simple -DartifactId=myapp -DgroupId=com.example

#warとかearとかejbのprojectを作成
$ mvn archetype:create -DarchetypeArtifactId=ee5-archetype-war-jsf -DarchetypeGroupId=sample.plugin -DarchetypeVersion=1.1 -DartifactId=myapp-war -DgroupId=com.example
$ mvn archetype:create -DarchetypeArtifactId=ee5-archetype-ejb -DarchetypeGroupId=sample.plugin -DarchetypeVersion=1.1 -DartifactId=myapp-ejb -DgroupId=com.example
$ mvn archetype:create -DarchetypeArtifactId=ee5-archetype-ear -DarchetypeGroupId=sample.plugin -DarchetypeVersion=1.1 -DartifactId=myapp-ear -DgroupId=com.example
[/shell]

自動的に下記のような構成になっている。
[shell]
myapp
|– myapp-ear/
| `– pom.xml
|– myapp-ejb/
| |– pom.xml
| `– src/
| |– main/
| | |– java/
| | | `– com/
| | | `– example/
| | | |– Sample.java
| | | `– SampleImpl.java
| | `– resources/
| | `– META-INF/
| | `– ejb-jar.xml
| `– test/
| `– java/
| `– com/
| `– example/
| `– SampleImplTest.java
|– myapp-war/
| |– pom.xml
| `– src/
| `– main/
| |– java/
| | `– com/
| | `– example/
| | `– Page.java
| |– resources/
| `– webapp/
| |– META-INF/
| | `– context.xml
| |– WEB-INF/
| | |– faces-config.xml
| | `– web.xml
| |– index.html
| `– page.jsp
|– pom.xml
`– src/
`– site/
|– apt/
| `– index.apt
`– site.xml
[/shell]

top level projectのmyappのpom.xmlにモジュールが追加されている。
[xml]
<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.example</groupId>
<artifactId>myapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<distributionManagement>
<site>
<id>website</id>
<url>scp://webhost.company.com/www/website</url>
</site>
</distributionManagement>
<modules>
<module>myapp-war</module>
<module>myapp-ejb</module>
<module>myapp-ear</module>
</modules>
</project>
[/xml]

maven packageする。(myapp.earの作成)
[shell]
$ cd ~/src/myapp
$ ls
myapp-ear/ myapp-ejb/ myapp-war/ pom.xml src/

$ mvn package
[INFO] Scanning for projects…
:
$ ls myapp-ear/target/
application.xml myapp/ myapp.ear
[/shell]

う〜んmavenカッチョよすぎる。。 antの1024倍はカッチョよい。
あとおまけ。GrassFishはこれでear deployらしい。ほんと?(確認してない)
いくらCoCといえども、これはdefaultなさそうなので、さすがに設定必要そうだけど。

[shell]
$$ASROOT/bin/asadmin deploy myapp-ear/target/myapp.ear
[/shell]

JavaEE6とJBoss AS 7とかGrassFish v3.1の組み合わせも相当よさげ〜。