*JAX-RSの部分を@emaggameさんからご指摘いただいたので、修正しました
JPAをちょこちょこ触ってきましたが、そろそろEE系のものも使ってみた方が面白いかなぁと思い、これまでずっと手を出してこなかったJava EEに踏み込んでみることにしました。
使うアプリケーションサーバは…やっぱりJBoss ASかなぁ。あと、WildFlyは開発中ですし、素直にJBoss AS 7にすることにします。
言語は、Scalaで!
Scalaを使うなら他のフレームワークあるじゃん?って意見もあろうかと思いますが、仕事上はこっちの方が近いので、Java EEにも少し触れていこうと思うのです。
なので、Scalaを使うのは完全に趣味ですが。
JBoss AS 7のインストール
オフィシャルサイトから、アーカイブをダウンロード。
JBoss Application Server
http://www.jboss.org/jbossas
自分は、「jboss-as-7.1.1.Final.zip」をダウンロードしました。展開すれば、インストールはお終いです。
$ unzip jboss-as-7.1.1.Final.zip
以降、これで展開してできるディレクトリを「$JBOSS_HOME」と呼びます。
$ ll $JBOSS_HOME 合計 340 drwxr-xr-x 10 xxxxx xxxxx 4096 3月 10 2012 ./ drwxrwxr-x 3 xxxxx xxxxx 4096 11月 4 18:20 ../ -rw-r--r-- 1 xxxxx xxxxx 26530 3月 10 2012 LICENSE.txt -rw-r--r-- 1 xxxxx xxxxx 2421 3月 10 2012 README.txt drwxr-xr-x 3 xxxxx xxxxx 4096 3月 10 2012 appclient/ drwxr-xr-x 4 xxxxx xxxxx 4096 3月 10 2012 bin/ drwxr-xr-x 4 xxxxx xxxxx 4096 3月 10 2012 bundles/ -rw-r--r-- 1 xxxxx xxxxx 2451 3月 10 2012 copyright.txt drwxr-xr-x 4 xxxxx xxxxx 4096 3月 10 2012 docs/ drwxr-xr-x 5 xxxxx xxxxx 4096 3月 10 2012 domain/ -rw-r--r-- 1 xxxxx xxxxx 266549 3月 10 2012 jboss-modules.jar drwxr-xr-x 13 xxxxx xxxxx 4096 3月 10 2012 modules/ drwxr-xr-x 8 xxxxx xxxxx 4096 11月 4 18:24 standalone/ drwxr-xr-x 2 xxxxx xxxxx 4096 3月 10 2012 welcome-content/
ちなみに、起動は以下のコマンドで。
$ $JBOSS_HOME/bin/standalone.sh
XA DataSourceの作成
JPAで、トランザクション管理可能なDataSourceが欲しかったので、XA DataSourceを作成することにしました。
…といっても、今回はトランザクション管理までやりませんでしたけどね。
最近のJBossの本を読むと、管理CLIからmoduleコマンドでJDBCドライバをモジュールとしてインストールできるようなのですが、コミュニティ版のJBoss AS 7は、それが入る前に止まったっぽいので、手動で作成します。
最初は、単にJDBCドライバをデプロイしようとしたのですが、それだとXAは作れないんですって。ここでまた、少々ハマりました…。
追加するドライバのJARは、MySQLのもので「mysql-connector-java-5.1.26.jar」とします。
「$JBOSS_HOME/modules」ディレクトリに移動します。
$ cd $JBOSS_HOME/modules/
$ mkdir -p com/mysql/main $ cd com/mysql/main/
ここに、ドライバのJARをコピーします。
$ cp /path/to/mysql-connector-java-5.1.26.jar ./.
続いて、以下の内容で「module.xml」ファイルを作成します。
module.xml
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.1" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.26.jar"/> <!-- Insert resources here --> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
管理CLIに接続します。
$ $JBOSS_HOME/bin/jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] connect [standalone@localhost:9999 /]
XA DataSourceを登録します。管理上のDataSourceの名前は「mysqlXaDs」で、JNDI名は「java:jboss/datasources/mysqlXaDs」とします。
[standalone@localhost:9999 /] cd /subsystem=datasources ## 登録したモジュールを、JDBCドライバとして登録する [standalone@localhost:9999 subsystem=datasources] ./jdbc-driver=mysql-driver:add(driver-name=mysql-driver,driver-module-name=com.mysql) {"outcome" => "success"} ## XA DataSourceの作成 [standalone@localhost:9999 subsystem=datasources] xa-data-source add --name=mysqlXaDs --jndi-name=java:jboss/datasources/mysqlXaDs --driver-name=mysql-driver ## 作成したデータソースの、接続先などの設定 [standalone@localhost:9999 subsystem=datasources] cd /subsystem=datasources/xa-data-source=mysqlXaDs [standalone@localhost:9999 xa-data-source=mysqlXaDs] ./xa-datasource-properties=ServerName:add(value=localhost) {"outcome" => "success"} [standalone@localhost:9999 xa-data-source=mysqlXaDs] ./xa-datasource-properties=PortNumber:add(value=3306) {"outcome" => "success"} [standalone@localhost:9999 xa-data-source=mysqlXaDs] ./xa-datasource-properties=DatabaseName:add(value=test) {"outcome" => "success"} [standalone@localhost:9999 xa-data-source=mysqlXaDs] xa-data-source --name=mysqlXaDs --user-name=kazuhira [standalone@localhost:9999 xa-data-source=mysqlXaDs] xa-data-source --name=mysqlXaDs --password=password [standalone@localhost:9999 xa-data-source=mysqlXaDs] xa-data-source enable --name=mysqlXaDs
ここまでできたら、1度コンソールを変えます。
登録したJDBCドライバを、XAとして設定します。以下のディレクトリに移動して
$ cd $JBOSS_HOME/standalone/configuration/
「standalone.xml」というファイルに、すでにH2用のドライバの設定と先ほど登録したMySQLのドライバの設定が書かれていると思います。ここで、MySQLの方に「xa-datasource-class」というタグを追加して、以下の内容とします。
<drivers> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> <driver name="mysql-driver" module="com.mysql"> <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class> </driver> </drivers>
ここまでできたら、JBoss ASを再起動します。
再起動ができたら、接続テストをしてみます。
[standalone@localhost:9999 /] /subsystem=datasources/xa-data-source=mysqlXaDs:test-connection-in-pool { "outcome" => "success", "result" => [true] }
「success」と返ってくれば、成功です。
ビルドツール
では、いよいよJava EEアプリケーションを作ろうというところですが、Scalaで書くはいいのですが、ビルドツールはどうしましょう…。
Web Profileの範囲しか使わないなら、xsbt-web-pluginでWARを作れば大丈夫だよね!ってことで、sbtでいくことにしました。ムリな場面が出てきたら、Mavenに乗り換えます。
build.sbt
name := "javaee6-web-jboss" version := "0.0.1-SNAPSHOT" scalaVersion := "2.10.3" organization := "littlewings" seq(webSettings: _*) artifactName := { (version: ScalaVersion, module: ModuleID, artifact: Artifact) => //artifact.name + "." + artifact.extension "javaee6-web." + artifact.extension } libraryDependencies ++= Seq( "org.eclipse.jetty" % "jetty-webapp" % "9.0.6.v20130930" % "container", "javax" % "javaee-web-api" % "6.0" % "provided", "mysql" % "mysql-connector-java" % "5.1.26" % "provided" )
WARの名前が、「javaee6-web.war」となるように細工をしています。あと、プラグインの関係で、今回使いもしないJettyの依存関係が入っています…。
プラグインの設定。
project/plugins.sbt
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "0.4.2")
これで、sbtのコンソールで
> packageWar
と入力することで「javaee6-web.war」が作成されます。
JPA
では、アプリケーションの作成へ。依存関係の都合上、下の階層から書いていくのがいいいでしょうか?
というわけで、JPAから。
設定。
src/main/resources/META-INF/persistence.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_2_0.xsd" version="2.0"> <persistence-unit name="javaee6.web.pu" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:jboss/datasources/mysqlXaDs</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" /> </properties> </persistence-unit>
Entityのコード。
src/main/scala/javaee6/web/entity/User.scala
package javaee6.web.entity import scala.beans.BeanProperty import javax.persistence.{Column, Entity, Id, Persistence, Table, Version} object User { def apply(id: Int, firstName: String, lastName: String, age: Int): User = { val user = new User user.id = id user.firstName = firstName user.lastName = lastName user.age = age user } } @SerialVersionUID(1L) @Entity @Table(name = "user") class User extends Serializable { @Id @BeanProperty var id: Int = _ @Column(name = "first_name") @BeanProperty var firstName: String = _ @Column(name = "last_name") @BeanProperty var lastName: String = _ @Column @BeanProperty var age: Int = _ @Column(name = "version_no") @Version @BeanProperty var versionNo: Int = _ override def toString(): String = s"id = $id, firstName = $firstName, lastName = $lastName, age = $age, versionNo = $versionNo" }
今回は、@Tableアノテーションを使用しました。@Tableアノテーションを使ったのは、JBoss ASにデプロイした時に、これまで書いていた@Entityでテーブル名のマッピングを変えている方法だと、JPQLの解釈がちょっと変わったからです…。
EJB3.1
ステートレス・セッションBeanをひとつ。EntityManager使っていますけど、Readしかしていませんが…。
src/main/scala/javaee6/web/service/UserService.scala
package javaee6.web.service import scala.collection.JavaConverters._ import javax.ejb.{Local, LocalBean, Stateless} import javax.persistence.{EntityManager, PersistenceContext} import javaee6.web.entity.User @Stateless @LocalBean class UserService { @PersistenceContext(unitName = "javaee6.web.pu") var entityManager: EntityManager = _ def findAll: List[User] = entityManager .createQuery("SELECT u FROM User u") .getResultList .asScala .toList .asInstanceOf[List[User]] }
JAX-RS
実装には、RESTEasyを使用します。今回、ここが1番てこずりました…。
@emaggameさんの指摘の結果、web.xmlはなくなりました!!ありがとうございます!
リソースクラス。
src/main/scala/javaee6/web/jaxrs/SimpleResource.scala
package javaee6.web.jaxrs import javax.inject.Inject import javax.ws.rs.{GET, Produces, Path} import javax.ws.rs.core.{MediaType, Response} import javaee6.web.service.UserService @Path("/simple") class SimpleResource { @Inject var userService: UserService = _ @GET @Path("user") @Produces(Array(MediaType.TEXT_HTML)) def users: Response = { val responseHtml = <html> <head> <meta charset="UTF-8" /> <title>ユーザ一覧</title> </head> <body> <h1>ユーザ一覧</h1> <table border="1"> <tr><th>ID</th><th>名前</th><th>年齢</th></tr> {userService.findAll.map { user => <tr> <td>{user.id}</td> <td>{user.lastName + " " + user.firstName}</td> <td>{user.age}</td> </tr> }} </table> </body> </html> Response.ok(responseHtml.toString).build } }
というわけでCDIを使っているので、以下のパスにファイルを作成。中身は空っぽです。
src/main/webapp/WEB-INF/beans.xml
デプロイするリソースを返すクラス。
src/main/scala/javaee6/web/jaxrs/SimpleApplication.scala
package javaee6.web.jaxrs import scala.collection.JavaConverters._ import javax.ws.rs.ApplicationPath import javax.ws.rs.core.Application @ApplicationPath("/") class SimpleApplication extends Application { override def getClasses: java.util.Set[Class[_]] = Set[Class[_]](classOf[SimpleResource]).asJava }
見直しの結果、驚異的に短くなりました(笑)。
あとは、これをパッケージングしてJBoss ASにデプロイします。
デプロイ
パッケージング。
> packageWar
デプロイ。
$ cp /path/to/javaee6-web.war $JBOSS_HOME/standalone/deployments/
デプロイメントスキャナがあるので、上記ディレクトリ配下に置けば、JBoss ASがデプロイしてくれます。再デプロイ時も、上書きコピーすればOKです。
アクセスする際には、以下のURLにアクセスすればテーブルに登録されているユーザ一覧が返ります。
http://localhost:8080/javaee6-web/simple/user/
テーブルの状態がこうだとして、
mysql> DESC user; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | id | int(9) | NO | PRI | 0 | | | first_name | varchar(10) | YES | | NULL | | | last_name | varchar(10) | YES | | NULL | | | age | int(3) | YES | | NULL | | | version_no | int(11) | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 5 rows in set (0.34 sec) mysql> SELECT * FROM user; +----+------------+-----------+------+------------+ | id | first_name | last_name | age | version_no | +----+------------+-----------+------+------------+ | 1 | カツオ | 磯野 | 11 | 0 | | 2 | ワカメ | 磯野 | 9 | 0 | | 3 | タラオ | フグ田 | 3 | 0 | +----+------------+-----------+------+------------+ 3 rows in set (0.01 sec)
生成されるHTMLは、こうなります。
<html> <head> <meta charset="UTF-8"/> <title>ユーザ一覧</title> </head> <body> <h1>ユーザ一覧</h1> <table border="1"> <tr><th>ID</th><th>名前</th><th>年齢</th></tr> <tr> <td>1</td> <td>磯野 カツオ</td> <td>11</td> </tr><tr> <td>2</td> <td>磯野 ワカメ</td> <td>9</td> </tr><tr> <td>3</td> <td>フグ田 タラオ</td> <td>3</td> </tr> </table> </body> </html>
とりあえず、1本通しきりました…。
参考URL)
http://planet.jboss.org/post/how_to_create_an_manage_datasources_in_as7
http://rikutoto.blogspot.jp/2013/04/jboss-as-7-datasource.html
https://access.redhat.com/site/documentation/en-US/JBoss_Enterprise_Application_Platform/6/html/Administration_and_Configuration_Guide/Example_MySQL_XA_Datasource1.html
https://access.redhat.com/site/documentation/ja-JP/JBoss_Enterprise_Application_Platform/6/html/Migration_Guide/chap-Migrate_Your_Application.html
参考書籍)
JBoss Enterprise Application Platform6 構築・運用パーフェクトガイド
- 作者: NTTオープンソースソフトウェアセンタ,レッドハット株式会社
- 出版社/メーカー: 技術評論社
- 発売日: 2013/06/22
- メディア: 大型本
- この商品を含むブログ (10件) を見る
Beginning Java EE 6~GlassFish 3で始めるエンタープライズJava (Programmer's SELECTION)
- 作者: Antonio Goncalves,日本オラクル株式会社,株式会社プロシステムエルオーシー
- 出版社/メーカー: 翔泳社
- 発売日: 2012/03/09
- メディア: 大型本
- 購入: 5人 クリック: 147回
- この商品を含むブログ (29件) を見る
- 作者: Bill Burke,arton,菅野良二
- 出版社/メーカー: オライリージャパン
- 発売日: 2010/08/23
- メディア: 大型本
- 購入: 28人 クリック: 804回
- この商品を含むブログ (41件) を見る