読者です 読者をやめる 読者になる 読者になる

in the mythosil

Rhythm & Biology.

Weld: Java SE環境でCDI利用

  • Java EEのアプリケーションコンテナを利用せず、Java SE環境でCDIを利用する方法。
  • CDIコンテナにはWeldを利用。

ソースコード

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mythosil</groupId>
    <artifactId>weldse</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.jboss.weld</groupId>
            <artifactId>weld-se</artifactId>
            <version>1.0.1-Final</version>
        </dependency>
    </dependencies>
</project>

WeldApplication.java

package com.mythosil.weldse;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;

@Singleton
public class WeldApplication {
    
    @Inject
    private Calc calc;
    
    public void run() {
        System.out.println(calc.add(1, 3));
    }
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("WeldApplication: PostConstruct");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("WeldApplication: PreDestroy");
    }
    
    public static void main(String[] args) {
        Weld weld = new Weld();
        WeldContainer container = weld.initialize();
        WeldApplication app = container.instance().select(WeldApplication.class).get();
        app.run();
        weld.shutdown();
    }
    
}

Calc.java

package com.mythosil.weldse;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class Calc {
    
    public int add(int a, int b) {
        return a + b;
    }
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("Calc: PostConstruct");
    }
    
    @PreDestroy
    public void preDestroy() {
        System.out.println("Calc: PreDestroy");
    }
    
}

実行

$ mvn exec:java -Dexec.mainClass=com.mythosil.weldse.WeldApplication                                      [~/NetBeansProjects/weldse]
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building weldse 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.3.2:java (default-cli) @ weldse ---
[WARNING] Warning: killAfter is now deprecated. Do you need it ? Please comment on MEXEC-6.
70 [com.mythosil.weldse.WeldApplication.main()] INFO org.jboss.weld.Version - WELD-000900 1.0.1 (Final)
88 [com.mythosil.weldse.WeldApplication.main()] INFO org.jboss.weld.Bootstrap - WELD-000101 Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
570 [com.mythosil.weldse.WeldApplication.main()] WARN org.jboss.interceptor.model.InterceptionTypeRegistry - Class 'javax.ejb.PostActivate' not found, interception based on it is not enabled
571 [com.mythosil.weldse.WeldApplication.main()] WARN org.jboss.interceptor.model.InterceptionTypeRegistry - Class 'javax.ejb.PrePassivate' not found, interception based on it is not enabled
Calc: PostConstruct
WeldApplication: PostConstruct
4
WeldApplication: PreDestroy
Calc: PreDestroy
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.856 s
[INFO] Finished at: 2014-10-22T23:25:21+09:00
[INFO] Final Memory: 11M/114M
[INFO] ------------------------------------------------------------------------

CDI 2.0

WildFly: JBoss Forgeによるアプリケーション開発

環境

プロジェクト作成

Forge Consoleを開きます

  • Show View → Forge Console
  • 緑の▶ボタンを押して起動
    • Forge 2.7.2.Finalを起動 (1.4.4.Finalではない)

新規プロジェクトを作成します

  • プロジェクト名: forge-proj
  • パッケージ名: com.mythosil.forge
[workspace]$ project-new --named forge-proj --topLevelPackage com.mythosil.forge --type war
***SUCCESS*** Project named 'forge-proj' has been created.

[forge-proj]$ ls
pom.xml  src  target

forgeのプロンプトがディレクトリ名(=プロジェクト名)になっています

エンティティ作成

  • エンティティクラス名: Person
[forge-proj]$ jpa-new-entity --named Person
***SUCCESS*** Persistence (JPA) is installed.
***SUCCESS*** Entity com.mythosil.forge.model.Person created

[Person.java]$ ls

[fields]
id::java.lang.Long  version::int

[methods]
equals(java.lang.Object)::boolean
getId()::java.lang.Long
getVersion()::int
hashCode()::int
setId(java.lang.Long)::void
setVersion(int)::void
toString()::java.lang.String

jap-new-entityコマンドでは、エンティティクラスの作成だけでなく、persistence.xmlの作成やpom.xmlの修正(依存追加)を行ってくれます

Java EEのバージョンは6.0、JPAのバージョンは2.0で作成されます
(Java EE 7に変更したければ手作業で書き換えるしかない?)

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.jboss.spec</groupId>
      <artifactId>jboss-javaee-6.0</artifactId>
      <version>3.0.2.Final</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.0-api</artifactId>
    <scope>provided</scope>
  </dependency>
</dependencies>

データソースとしてはH2が利用されます

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="forge-proj-persistence-unit" transaction-type="JTA">
    <description>Forge Persistence Unit</description>
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.transaction.flush_before_completion" value="true"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
    </properties>
  </persistence-unit>
</persistence>

エンティティにフィールド追加

  • フィールド名: name
  • 型: String
  • 長さ: 50
[Person.java]$ jpa-new-field --named name --type String --length 50
***SUCCESS*** Field name created

RESTエンドポイント作成

Personエンティティを元に作成してみます

(Eclipse上で実行するとエラーが出る場合は、CLIで試してみて下さい)

[Person.java]$ rest-generate-endpoints-from-entities --targets com.mythosil.forge.model.Person
***SUCCESS*** JAX-RS has been installed.
***SUCCESS*** Endpoint created

この際、RESTエンドポイントクラス作成と同時に、Personクラスに@XmlRootElementアノテーションが付加されます
また、エンティティ作成時と同様、pom.xmlが自動で修正されます

<dependency>
  <groupId>org.jboss.spec.javax.servlet</groupId>
  <artifactId>jboss-servlet-api_3.0_spec</artifactId>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.jboss.spec.javax.ws.rs</groupId>
  <artifactId>jboss-jaxrs-api_1.1_spec</artifactId>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.jboss.spec.javax.ejb</groupId>
  <artifactId>jboss-ejb-api_3.1_spec</artifactId>
  <scope>provided</scope>
</dependency>

ビルド

[PersonEndpoint.java]$ build
***SUCCESS*** Build Success

デプロイ

jboss-cli.shを利用してデプロイします
(wildflyは事前に起動しておく)

$ cd /path/to/forge-proj
$ $JBOSS_HOME/bin/jboss-cli.sh -c --command="deploy target/forge-proj-1.0.0-SNAPSHOT.war"

実行

$ curl -XPOST 'http://localhost:8080/forge-proj-1.0.0-SNAPSHOT/rest/people' \
    -d '{"name":"my name"}' \
    -H "Content-Type: application/json"
$ curl 'http://localhost:8080/forge-proj-1.0.0-SNAPSHOT/rest/people/1'
{"id":1,"version":0,"name":"my name"}

まとめ

  • 開発のベースはforgeで作ると楽
  • Forge Consoleが遅い・不安定
    • 正直、まともに動かない
    • Eclipse上ではなくCLIであれば普通に動く

参考

WildFly: Arquillianを利用したテスト

WildFly+Arquillianでテストを実行してみたログ

環境

プロジェクト新規作成

  1. 新規プロジェクト → Maven → Webアプリケーション
  2. プロジェクト名: arq-base
  3. パッケージ: com.mythosil.arqbase
  4. サーバ: WildFly
  5. Java EE バージョン: Java EE 7 Web

テスト対象クラスの用意

まずはシンプルなセッションBeanをテスト対象クラスとして用意します

  • 新規 → セッションBean
    • EJB名: SimpleBean
    • 場所: ソース・パッケージ
    • パッケージ: com.mythosil.arqbase
    • セッションのタイプ: ステートレス
package com.mythosil.arqbase;

import javax.ejb.Stateless;

@Stateless
public class SimpleBean {
    public String hello(String name) {
        return String.format("Hello, %s", name);
    }
}

pom.xmlの用意

  • repositories
  • dependencyManagement
    • WildFlyとArquillianのBOMを追加
  • dependencies
    • EJBJUnit、Arquillianを依存に追加
  • profile
    • managed版とremote版をそれぞれ用意
    • arquillianの依存もそれぞれに合わせた物を依存に追加
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mythosil</groupId>
    <artifactId>arq-base</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>arq-base</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.jboss.spec.javax.ejb</groupId>
            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.protocol</groupId>
            <artifactId>arquillian-protocol-servlet</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.wildfly.bom</groupId>
                <artifactId>jboss-javaee-7.0-with-all</artifactId>
                <version>8.1.0.Final</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.jboss.arquillian</groupId>
                <artifactId>arquillian-bom</artifactId>
                <version>1.1.5.Final</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.6</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>7.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
    <profiles>
        <profile>
            <id>arq-wildfly-managed</id>
            <dependencies>
                <dependency>
                    <groupId>org.wildfly</groupId>
                    <artifactId>wildfly-arquillian-container-managed</artifactId>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </profile>
        <profile>
            <id>arq-wildfly-remote</id>
            <dependencies>
                <dependency>
                    <groupId>org.wildfly</groupId>
                    <artifactId>wildfly-arquillian-container-remote</artifactId>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
    
    <repositories>
        <repository>
            <id>JBoss Repository</id>
            <url>https://repository.jboss.org/nexus/content/groups/public/</url>
        </repository>
    </repositories>

</project>

テストの用意

  • 新規 → JUnitテスト
    • クラス名: SimpleBeanTest
    • 場所: テスト・パッケージ
    • パッケージ: com.mythosil.arqbase
  • RunWith
    • Arquillian.classを指定
  • テスト対象クラス
  • アーカイブ作成
    • Deploymentアノテーションを利用
    • ShrinkWrapクラスを利用し、テスト時にWildFlyにデプロイするアーカイブを生成
package com.mythosil.arqbase;

import javax.ejb.EJB;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class SimpleBeanTest {
    @EJB
    SimpleBean target;
    
    @Test
    public void testHello() {
        String actual = target.hello("myname");
        assertEquals("Hello, myname", actual);
    }
    
    @Deployment
    public static Archive<?> createTestArchive() {
        return ShrinkWrap.create(WebArchive.class)
                .addClass(SimpleBean.class);
    }
}

arquillian.xmlの用意

  • 新規 → XMLドキュメント
    • ファイル名: arquillian
    • フォルダ: src/test/resources/META-INF
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
    
    <container qualifier="wildfly-managed" default="true">
        <configuration>
            <property name="jbossHome">WildFlyのインストール先</property>
        </configuration>
    </container>
    
    <container qualifier="wildfly-remote" default="false">
        <configuration>
            <property name="managementPort">9990</property>
            <property name="managementAddress">WildFlyサーバのアドレス</property>
            <property name="username">ユーザ名</property>
            <property name="password">パスワード</property>
        </configuration>
    </container>
    
</arquillian>

テスト実行

# managed版の実行
$ mvn clean test -Parq-wildfly-managed
...(中略)...
Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 20.780 s
[INFO] Finished at: 2014-09-04T01:04:17+09:00
[INFO] Final Memory: 29M/221M
[INFO] ------------------------------------------------------------------------

# remote版の実行
$ mvn clean test -Parq-wildfly-remote

テスト対象エンティティクラスの用意

エンティティクラスもテストしてみます
DBにはH2(インメモリ)を利用します

  • 新規 → エンティティクラス
    • クラス名: Person
    • 場所: ソース・パッケージ
    • パッケージ: com.mythosil.arqbase
    • 主キー型: Long
    • 持続性ユニット名: arqbasePU
    • 永続性プロバイダ: Hibernate (JPA2.1)
    • データ・ソース: java:jboss/datasources/test
package com.mythosil.arqbase;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    /* Setter, Getter */
}

pom.xml修正

<dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.1-api</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.jboss.spec.javax.transaction</groupId>
    <artifactId>jboss-transaction-api_1.2_spec</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.enterprise</groupId>
    <artifactId>cdi-api</artifactId>
    <scope>provided</scope>
</dependency>

テスト用datasource作成

  • テスト用DBとしてH2(インメモリ)を利用
  • 新規 → XMLドキュメント
    • ファイル名: test-ds
    • フォルダ: src/test/resources/WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<datasources  xmlns="http://www.jboss.org/ironjacamar/schema">
    <datasource jndi-name="java:jboss/datasources/test" pool-name="TestDS" enabled="true" use-java-context="true">
        <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
        <driver>h2</driver>
        <security>
            <user-name>sa</user-name>
            <password>sa</password>
        </security>
    </datasource>
</datasources>

テストの用意

  • 新規 → JUnitテスト
    • クラス名: PersonTest
    • 場所: テスト・パッケージ
    • パッケージ: com.mythosil.arqbase
package com.mythosil.arqbase;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.UserTransaction;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class PersonTest {
    @PersistenceContext
    EntityManager em;
    @Inject
    UserTransaction tx;
    
    @Test
    public void testPersist() throws Exception {
        Person target = new Person();
        target.setName("myname");
        
        tx.begin();
        em.joinTransaction();
        em.persist(target);
        tx.commit();
        em.clear();
        
        Person p = em.find(Person.class, 1L);
        assertEquals("myname", p.getName());
    }
    
    @Deployment
    public static Archive<?> createTestArchive() {
        return ShrinkWrap.create(WebArchive.class)
                .addClass(Person.class)
                .addAsResource("META-INF/persistence.xml")
                .addAsWebInfResource("WEB-INF/test-ds.xml")
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }
}

テスト実行

$ mvn clean test -Parq-wildfly-managed

WildFly: ポート番号の変更方法

ポートを変更する方法を何種類か、備忘録

デフォルト

  • HTTPポート: 8080
  • 管理ポート: 9990

起動時にポート番号指定

  • HTTPポート: 18080
  • 管理ポート: 19990
$ ./standalone.sh \
    -Djboss.http.port=18080 \
    -Djboss.management.http.port=19990

起動時にオフセット値指定

オフセット値を指定すると、HTTPポート、管理ポートなど、全てのポート番号がオフセット値ぶんだけ加算されて起動する

同一マシンでWildFly複数立ち上げようとするとポートの衝突が問題になるが、オフセットを利用することで、全ポート番号を指定する必要がなくなる

$ ./standalone.sh -Djboss.socket.binding.port-offset=100

ちなみに、ポート番号指定も同時にすると、オフセット値は無視される(ポート番号指定されていないものだけにオフセット値が適用される)

standalone.xmlを直接編集

変数の部分にダイレクトに数値を埋め込む

書き方を真似すれば、デフォルトのポート番号を変更して、起動時にさらに変更可能にしておくこともできる

<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
    <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
    <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
    <socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
    <socket-binding name="http" port="${jboss.http.port:8080}"/>
    <socket-binding name="https" port="${jboss.https.port:8443}"/>
    <socket-binding name="txn-recovery-environment" port="4712"/>
    <socket-binding name="txn-status-manager" port="4713"/>
    <outbound-socket-binding name="mail-smtp">
        <remote-destination host="localhost" port="25"/>
    </outbound-socket-binding>
</socket-binding-group>

CLIツールで編集

write-attributeコマンドを利用してポート番号を変更(standalone.xmlが書き変わる)

reloadコマンドを実行するとWildFlyが新しいポートで再起動する

$ ./jboss-cli.sh -c
[standalone@localhost:9990 /] /socket-binding-group=standard-sockets/socket-binding=http:write-attribute(name="port",value="18080")
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
[standalone@localhost:9990 /] /socket-binding-group=standard-sockets/socket-binding=management-http:write-attribute(name="port",value="19990")
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
[standalone@localhost:9990 /] :reload
{
    "outcome" => "success",
    "result" => undefined
}

WildFly: MySQLをデータソースとして利用 (CLI設定)

CLIツールにこだわって、WildFlyへのMySQLのドライバインストール、データソース追加までやってみます。

WildFlyのバージョンは8.1.0.Finalです。

ドライバのダウンロード

WildFlyにはドライバは標準ではついてこない(?)ため、ダウンロードしてきます。

$ cd $WILDFLY_HOME/bin
$ curl -LO http://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.31.tar.gz
$ tar xvfz mysql-connector-java-5.1.31.tar.gz

ドライバのデプロイ

さきほどダウンロードしたドライバファイルをWildFlyにデプロイします。

$ ./jboss-cli.sh -c
[standalone@localhost:9990 /] module add --name=org.mysql --resources=mysql-connector-java-5.1.31/mysql-connector-java-5.1.31-bin.jar --dependencies=javax.api,javax.transaction.api
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mysql:add(driver-module-name=org.mysql,driver-name=mysql,driver-class-name=com.mysql.jdbc.Driver)
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=mysql:read-resource
{
    "outcome" => "success",
    "result" => {
        "deployment-name" => undefined,
        "driver-class-name" => "com.mysql.jdbc.Driver",
        "driver-datasource-class-name" => undefined,
        "driver-major-version" => undefined,
        "driver-minor-version" => undefined,
        "driver-module-name" => "org.mysql",
        "driver-name" => "mysql",
        "driver-xa-datasource-class-name" => undefined,
        "jdbc-compliant" => undefined,
        "module-slot" => undefined,
        "xa-datasource-class" => undefined
    }
}

データソースの追加

データソースの追加から、接続テストまでやります。

[standalone@localhost:9990 /] /subsystem=datasources/data-source=mysqlds:add(jndi-name=java:jboss/datasources/mysqlds,driver-name=mysql,connection-url=jdbc:mysql://localhost:3306/dbname,user-name=dbuser,password=dbpass)            
{"outcome" => "success"}
[standalone@localhost:9990 /] /subsystem=datasources/data-source=mysqlds:test-connection-in-pool
{
    "outcome" => "success",
    "result" => [true]
}
[standalone@localhost:9990 /] /subsystem=datasources/data-source=mysqlds:read-resource
{
    "outcome" => "success",
    "result" => {
        "allocation-retry" => undefined,
        "allocation-retry-wait-millis" => undefined,
        "allow-multiple-users" => false,
        "background-validation" => undefined,
        "background-validation-millis" => undefined,
        "blocking-timeout-wait-millis" => undefined,
        "capacity-decrementer-class" => undefined,
        "capacity-decrementer-properties" => undefined,
        "capacity-incrementer-class" => undefined,
        "capacity-incrementer-properties" => undefined,
        "check-valid-connection-sql" => undefined,
        "connection-listener-class" => undefined,
        "connection-listener-property" => undefined,
        "connection-properties" => undefined,
        "connection-url" => "jdbc:mysql://localhost:3306/dbname",
        "datasource-class" => undefined,
        "driver-class" => undefined,
        "driver-name" => "mysql",
        "enabled" => true,
        "exception-sorter-class-name" => undefined,
        "exception-sorter-properties" => undefined,
        "flush-strategy" => undefined,
        "idle-timeout-minutes" => undefined,
        "initial-pool-size" => undefined,
        "jndi-name" => "java:jboss/datasources/mysqlds",
        "jta" => true,
        "max-pool-size" => undefined,
        "min-pool-size" => undefined,
        "new-connection-sql" => undefined,
        "password" => "dbpass",
        "pool-prefill" => undefined,
        "pool-use-strict-min" => undefined,
        "prepared-statements-cache-size" => undefined,
        "query-timeout" => undefined,
        "reauth-plugin-class-name" => undefined,
        "reauth-plugin-properties" => undefined,
        "security-domain" => undefined,
        "set-tx-query-timeout" => false,
        "share-prepared-statements" => false,
        "spy" => false,
        "stale-connection-checker-class-name" => undefined,
        "stale-connection-checker-properties" => undefined,
        "track-statements" => "NOWARN",
        "transaction-isolation" => undefined,
        "url-delimiter" => undefined,
        "url-selector-strategy-class-name" => undefined,
        "use-ccm" => true,
        "use-fast-fail" => false,
        "use-java-context" => true,
        "use-try-lock" => undefined,
        "user-name" => "dbuser",
        "valid-connection-checker-class-name" => undefined,
        "valid-connection-checker-properties" => undefined,
        "validate-on-match" => false,
        "statistics" => {
            "jdbc" => undefined,
            "pool" => undefined
        }
    }
}

追加された設定

$ diff standalone/configuration/standalone.xml{.org,}
148a149,156
>                 <datasource jndi-name="java:jboss/datasources/mysqlds" pool-name="mysqlds" enabled="true">
>                     <connection-url>jdbc:mysql://localhost:3306/dbname</connection-url>
>                     <driver>mysql</driver>
>                     <security>
>                         <user-name>dbuser</user-name>
>                         <password>dbpass</password>
>                     </security>
>                 </datasource>
152a161,163
>                     <driver name="mysql" module="org.mysql">
>                         <driver-class>com.mysql.jdbc.Driver</driver-class>
>                     </driver>

サンプルアプリケーション

MySQL内のデータを読み書きする小さなWebアプリを作ってみます。

テーブル作成

idフィールドとnameフィールドだけを持つbookテーブルを作成。

create table book (
  id int primary key auto_increment,
  name varchar(128) not null
);

プロジェクト作成

今回はNetBeans8.0を使います。

  1. 新規プロジェクト
  2. Java Web
  3. Webアプリケーション
  4. プロジェクト名「SampleApp」
  5. サーバはWildFlyを選択
  6. Pluginをインストールし、WildFlyをサーバに追加しておく

Webサービス作成

  1. 新規
  2. データベースからのRESTful Webサービス
  3. データソースはmysqldsを選択
  4. テーブルはbookを選択
  5. パッケージ名は今回はcom.mythosilとする
  6. ApplicationConfigの作成
  7. BookFacadeRESTクラス上で「Alt+Enter」で作成

デプロイ・動作確認

デプロイはNetBeans上で「実行」ボタンを押すだけ。

動作確認はcurlで行います。

$ curl 'http://localhost:8080/SampleApp/webresources/com.mythosil.book' -X POST -H "Content-Type: application/json" -d '{"name":"Book1"}'
$ curl 'http://localhost:8080/SampleApp/webresources/com.mythosil.book' -X POST -H "Content-Type: application/json" -d '{"name":"Book2"}'
$ curl 'http://localhost:8080/SampleApp/webresources/com.mythosil.book' -H "Accept: application/json" | python -mjson.tool
[
    {
        "id": 1,
        "name": "Book1"
    },
    {
        "id": 2,
        "name": "Book2"
    }
]

補足1: 設定変更

write-attributeコマンドを利用します。
設定変更後は:reloadが必要です。

[standalone@localhost:9990 /] /subsystem=datasources/data-source=mysqlds:write-attribute(name=connection-url,value=jdbc:mysql://localhost:3306/otherdb)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
[standalone@localhost:9990 /] :reload
{
    "outcome" => "success",
    "result" => undefined
}

補足2: データソースの削除

データソースに対してremoveコマンドを実行するだけです。

[standalone@localhost:9990 /] /subsystem=datasources/data-source=mysqlds:remove
{"outcome" => "success"}

参考資料