JavaEE7の環境構築

JavaEE7 JAX-RS アプリケーションの環境構築のメモです。

以下の環境で行いました。

- Java8
- Payara Server  4.1.1.164
- Eclipse Java EE IDE for Web Developers. Version: Neon.2 Release (4.6.2)
- Gradle 3.2.1

必要なEclipse Pluginです、Gradleで依存ライブラリやビルドを行います。

- Buildship: Eclipse Plug-ins for Gradle 1.0.21.v20161010-1640
- GlassFish Tools 16.3.0.201612160743

*****
### Payara Server Install

サイトからDownloadしたtar.gzを解凍して、任意のディレクトリに配置します。
> http://www.payara.fish/downloads

解凍したディレクトリ内の`glassfish/bin`にPATHを通します。

*****
### Eclipse

公式からインストーラーをDownloadして、インストールします。
> https://eclipse.org/downloads/
> インストール実行時にJavaEEを選択すること

Glassfishプラグインをインストール後、アプリケーションサーバを追加します。

- `Window` -> `Show View` -> `Servers` (表示済みならやらなくてOK)
- 右クリックから`New` -> `Server` -> `Glassfish`
- `Domain path`にPayaraServerをインストールしたディレクトリ内の`glassfish/domains/domain1`を設定して`Finish`
  - ex) `/Users/picotaro/app/payara41/glassfish/domains/domain1`

Glassfishサーバを起動します。

- 追加したGlassfishサーバを右クリック -> `Start`

http://localhost:4848 にアクセスすると管理画面が表示されます。

*****
### Create Project

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

```sh
$ gradle init --type java-library
```

`build.gradle`を編集します。

`compileOnly 'fish.payara.blue.extras:payara-embedded-all:4.1.1.164'`がJavaEEアプリケーション開発に必要な設定です。

```groovy:build.gradle
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'eclipse'

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    compile 'org.slf4j:slf4j-api:1.7.21'
    compile 'org.projectlombok:lombok:1.16.12'
    compile 'com.h2database:h2:1.4.191'

    compileOnly 'fish.payara.blue.extras:payara-embedded-all:4.1.1.164'

    testCompile 'junit:junit:4.12'
}

sourceSets {
    main.java.srcDirs += 'src/main/webapp'
}
```

eclipseでimportします。

- `File` -> `Import` -> `Gradle Project`
- `Project root directory`に作成したプロジェクトのpathを指定 -> `Finish`

プロジェクトの設定をします。

- importしたプロジェクトを右クリック -> `Project Facets`
- `Java`, `Dynamic Web Module`, `GlassFish Web Extensions`にチェックを入れる -> `OK`

エントリポイントを作成します。

```java:sample.payara.Application
@ApplicationPath("/")
public class Application extends ResourceConfig {
    public Application() {
        packages(this.getClass().getPackage().getName());
        register(JacksonFeature.class);
    }
}
```

APIのcontrollerを追加します。

```java:sample.payara.controller.SampleController
@Path("/sample")
public class SampleController {
    @GET
    @Produces(MediaType.TEXT_HTML)
    public String index() {
        return "Hello Payara!!";
    }
}
```

*****
### deploy

アプリケーションをPayaraServerにデプロイします。

- GlassFishサーバを右クリック -> `Add and Remove`
- プロジェクトを選択して`Add >` -> `Finish`

デプロイに成功すると、consoleにログが出力されます。
> ex) `2017-01-09T07:20:11.404+0900|情報: Payara was successfully deployed in 7,352 milliseconds.`

http://localhost:8080/{context_path}/sample にアクセスすると`Hello Payara!!`と表示されます。
> {context_path}はプロジェクト名です

*****
### glassfish-resources.xml

データベースの接続情報を設定します。

`src/main/webapp/WEB-INF/glassfish-resources.xml`を作成します。

`jdbc-connection-pool`を`jdbc-resource`として設定します。

次の`persistence.xml`の設定では、`jndi-name`で設定した名前を参照するようにします。

> DBは、H2データベースをサーバモードで起動しています。

```xml:glassfish-resources.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <!-- apple -->
    <jdbc-resource pool-name="apple_pool" jndi-name="jdbc/apple_data_source"></jdbc-resource>
    <jdbc-connection-pool name="apple_pool" datasource-classname="org.h2.jdbcx.JdbcDataSource">
        <property name="user" value="sa"></property>
        <property name="password" value=""></property>
        <property name="driverClass" value="org.h2.Driver"></property>
        <property name="url" value="jdbc:h2:tcp://localhost/~/apple;MODE=MySQL"></property>
    </jdbc-connection-pool>
    <!-- pineapple -->
    <jdbc-resource pool-name="pineapple_pool" jndi-name="jdbc/pineapple_data_source"></jdbc-resource>
    <jdbc-connection-pool name="pineapple_pool" datasource-classname="org.h2.jdbcx.JdbcDataSource">
        <property name="user" value="sa"></property>
        <property name="password" value=""></property>
        <property name="driverClass" value="org.h2.Driver"></property>
        <property name="url" value="jdbc:h2:tcp://localhost/~/pineapple;MODE=MySQL"></property>
    </jdbc-connection-pool>
</resources>
```

asadminコマンドで、GlassFishに登録します。

```sh
$ asadmin add-resources src/main/webapp/WEB-INF/glassfish-resources.xml
```

*****
### persistence.xml

`src/main/resources/META-INF/persistence.xml`を作成します。

`persistence-unit`内で、`jta-data-source`を設定します。
`jta-data-source`は、`glassfish-resources.xml`で設定した`jndi-name`を参照します。

> `property`でデプロイ時にsqlを実行するように設定していますが、１つ目の`persistence-unit`のscriptしか実行されませんでした

```xml:persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence
    version="2.1"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="apple" transaction-type="JTA">
        <!-- `src/main/webapp/WEB-INF/glassfish-resources.xml`で設定しているjdbc-resource -->
        <jta-data-source>jdbc/apple_data_source</jta-data-source>
        <properties>
            <!-- アプリケーションのデプロイ時に実行されるアクション -->
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
            <!-- create table -->
            <property name="javax.persistence.schema-generation.create-source" value="script"/>
            <property name="javax.persistence.schema-generation.create-script-source" value="META-INF/sql/apple/create.sql"/>
            <!-- drop table -->
            <property name="javax.persistence.schema-generation.drop-source" value="script"/>
            <property name="javax.persistence.schema-generation.drop-script-source" value="META-INF/sql/apple/drop.sql"/>
            <!-- load data -->
            <property name="javax.persistence.sql-load-script-source" value="META-INF/sql/apple/load.sql"/>
            <property name="eclipselink.logging.level" value="FINE"/>
        </properties>
    </persistence-unit>
    <persistence-unit name="pineapple" transaction-type="JTA">
        <!-- `src/main/webapp/WEB-INF/glassfish-resources.xml`で設定しているjdbc-resource -->
        <jta-data-source>jdbc/pineapple_data_source</jta-data-source>
        <properties>
            <!-- アプリケーションのデプロイ時に実行されるアクション -->
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
            <!-- create table -->
            <property name="javax.persistence.schema-generation.create-source" value="script"/>
            <property name="javax.persistence.schema-generation.create-script-source" value="META-INF/sql/pineapple/create.sql"/>
            <!-- drop table -->
            <property name="javax.persistence.schema-generation.drop-source" value="script"/>
            <property name="javax.persistence.schema-generation.drop-script-source" value="META-INF/sql/pineapple/drop.sql"/>
            <!-- load data -->
            <property name="javax.persistence.sql-load-script-source" value="META-INF/sql/pineapple/load.sql"/>
            <property name="eclipselink.logging.level" value="FINE"/>
        </properties>
    </persistence-unit>
</persistence>
```

EntityとDAOを作成します。

```java:sample.payara.model.SampleModel
@Entity
@Table(name = "sample_model")
@NoArgsConstructor
@AllArgsConstructor
public class SampleModel {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;

    @Column(name = "name")
    private String name = "";

    @Column(name = "created")
    private Date created = new Date();

    @Column(name = "updated")
    private Date updated = null;

    public SampleModel(long id, String name) {
        this.id = id;
        this.name = name;
    }
}
```

```java:sample.payara.dao.SampleModelDao
@Stateless
public class SampleModelDao {
    @PersistenceContext(unitName = "apple")
    private EntityManager em;

    public SampleModel sampleModel() {
        return new SampleModel(1, "hoge");
    }

    public List<SampleModel> findAll() {
        return em.createQuery("from SampleModel s order by s.id", SampleModel.class).getResultList();
    }

    public SampleModel findBy(Long id) {
        return em.find(SampleModel.class, id);
    }
}
```

controllerからDAOを呼び出すようにします。

```java
@Stateless
@Path("/sample")
public class SampleController {
    @Inject
    private SampleModelDao sampleModelDao;

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String index() {
        return "Hello Payara!!";
    }

    @GET
    @Path("list")
    @Produces(MediaType.APPLICATION_JSON)
    public List<SampleModel> list() {
        return sampleModelDao.findAll();
    }

    @GET
    @Path("search")
    @Produces(MediaType.APPLICATION_JSON)
    public SampleModel search(@QueryParam("id") Long id) {
        return this.sampleModelDao.findBy(id);
    }
}
```

再度、デプロイするとアクセスできます。

*****

上記のソースは以下です、参考になれば幸いです。
https://github.com/yamashiro0110/JavaEE/tree/master/Payara