Nablarchのブランクプロジェクトを作成した後に、使用するデータベースを切り替えるスクリプトを書く

# What's？

以前から、何度かNablarchを使ったMavenプロジェクトで使用するデータベースを切り替える記事を書いています。

https://qiita.com/charon/items/095a89b19421010160aa

https://qiita.com/charon/items/2c14ab849d3edfd9fe61

Nablarchのドキュメントにも切り替える手順は書かれています。

https://nablarch.github.io/docs/6u2/doc/application_framework/application_framework/blank_project/CustomizeDB.html

なのですが、これを手動で修正していくのはちょっとめんどうです。  
うまく置換できたりしないかな、ということでスクリプトを書いてみました。

Linux前提の手順とします。

# 環境

今回の環境はこちらです。

```shell
$ java --version
openjdk 17.0.12 2024-07-16
OpenJDK Runtime Environment (build 17.0.12+7-Ubuntu-1ubuntu222.04)
OpenJDK 64-Bit Server VM (build 17.0.12+7-Ubuntu-1ubuntu222.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /home/charon/.sdkman/candidates/maven/current
Java version: 17.0.12, vendor: Ubuntu, runtime: /usr/lib/jvm/java-17-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.15.0-122-generic", arch: "amd64", family: "unix"
```

Nablarchは6u2を使います。

切り替え先のデータベースは、PostgreSQLにします。こちらはDockerコンテナで用意します。

```shell
$ docker container run -it --rm -p 5432:5432 \
  -e POSTGRES_DB=web_db \
  -e POSTGRES_USER=web_user \
  -e POSTGRES_PASSWORD=web_password \
  --name postgres \
  postgres:16.4-bookworm
```

使用したDockerのバージョンはこちらです。

```shell
$ docker version
Client: Docker Engine - Community
 Version:           27.3.1
 API version:       1.47
 Go version:        go1.22.7
 Git commit:        ce12230
 Built:             Fri Sep 20 11:42:48 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          27.3.1
  API version:      1.47 (minimum version 1.24)
  Go version:       go1.22.7
  Git commit:       41ca978
  Built:            Fri Sep 20 11:41:09 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.22
  GitCommit:        7f7fdf5fed64eb6a7caf99b3e12efcf9d60e311c
 runc:
  Version:          1.1.14
  GitCommit:        v1.1.14-0-g2c9f560
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```

# ブランクプロジェクトを作成する

まずはベースになるブランクプロジェクトを作成します。

https://nablarch.github.io/docs/6u2/doc/application_framework/application_framework/blank_project/index.html

今回はウェブプロジェクトを対象にしようと思います。

Maven Archetype Pluginでプロジェクトを作成。

```shell
$ mvn archetype:generate \
  -DinteractiveMode=false \
  -DarchetypeGroupId=com.nablarch.archetype \
  -DarchetypeArtifactId=nablarch-web-archetype \
  -DarchetypeVersion=6u2 \
  -DgroupId=com.example \
  -DartifactId=hello-nablarch-web \
  -Dversion=0.0.1 \
  -Dpackage=com.example
```

プロジェクト内に移動。

```shell
$ cd hello-nablarch-web
```

# データベースに関する情報を文字列置換する

お題になっている、データベースを切り替えるために作成したスクリプトはこちらです。

```shell:switch-nablarch-database.sh
#!/bin/bash

set -eu

DATABASE_TYPE=＜使用するデータベースの種類＞
DIALECT_CLASS=＜ダイアレクトのクラス名＞
DRIVER_CLASS=＜JDBCドライバのクラス名＞
JDBC_URL=＜JDBC URL＞

DRIVER_DEPENDENCY_GROUP_ID=＜使用するJDBCドライバのgroupId＞
DRIVER_DEPENDENCY_ARTIFACT_ID=＜使用するJDBCドライバのartifactId＞
DRIVER_DEPENDENCY_VERSION=＜使用するJDBCドライバのバージョン＞

DB_USER=＜データベース接続ユーザー名＞
DB_PASSWORD=＜データベース接続パスワード＞
SCHEMA_NAME=＜データベースのスキーマ名＞
DB_ADMIN_USER=＜管理操作用データベース接続ユーザー名＞
DB_ADMIN_PASSWORD=＜管理操作用データベース接続パスワード＞

if [ ! -e pom.xml ]; then
    echo "操作対象のプロジェクト内（pom.xmlが配置されているディレクトリ）でスクリプトを実行してください"
    exit 1
fi

## JDBCドライバの依存関係を変更
perl -0777 -wpi -e 's!\s+<dependency>\s+?<groupId>com\.h2database</groupId>\s+?<artifactId>h2</artifactId>.+?</dependency>!\n     <dependency>\n       <groupId>'${DRIVER_DEPENDENCY_GROUP_ID}'</groupId>\n       <artifactId>'${DRIVER_DEPENDENCY_ARTIFACT_ID}'</artifactId>\n       <version>'${DRIVER_DEPENDENCY_VERSION}'</version>\n       <scope>runtime</scope>\n     </dependency>!sg' pom.xml

## gsp-dba-maven-pluginの接続パラメーターを変更
perl -wpi -e 's!<nablarch.db.jdbcDriver>.+</nablarch.db.jdbcDriver>!<nablarch.db.jdbcDriver>'${DRIVER_CLASS}'</nablarch.db.jdbcDriver>!; s!<nablarch.db.url>.+</nablarch.db.url>!<nablarch.db.url>'${JDBC_URL}'</nablarch.db.url>!; s!<nablarch.db.adminUser>.+</nablarch.db.adminUser>!<nablarch.db.adminUser>'${DB_ADMIN_USER}'</nablarch.db.adminUser>!; s!<nablarch.db.adminPassword>.+</nablarch.db.adminPassword>!<nablarch.db.adminPassword>'${DB_ADMIN_PASSWORD}'</nablarch.db.adminPassword>!; s!<nablarch.db.user>.+</nablarch.db.user>!<nablarch.db.user>'${DB_USER}'</nablarch.db.user>!; s!<nablarch.db.password>.+</nablarch.db.password>!<nablarch.db.password>'${DB_PASSWORD}'</nablarch.db.password>!; s!<nablarch.db.schema>.+</nablarch.db.schema>!<nablarch.db.schema>'${SCHEMA_NAME}'</nablarch.db.schema>!' pom.xml

## データベースへの接続パラメーターを変更
grep -rl 'nablarch.db.url=' src | xargs perl -wpi -e 's!nablarch.db.jdbcDriver=.+!nablarch.db.jdbcDriver='${DRIVER_CLASS}'!; s!nablarch.db.url=.+!nablarch.db.url='${JDBC_URL}'!; s!nablarch.db.user=.+!nablarch.db.user='${DB_USER}'!; s!nablarch.db.password=.+!nablarch.db.password='${DB_PASSWORD}'!; s!nablarch.db.schema=.+!nablarch.db.schema='${SCHEMA_NAME}'!'

## Dialect変更
grep -rl '<component name="dialect"' src | xargs perl -wpi -e 's!(.+<component name="dialect" class=)".+!$1"'${DIALECT_CLASS}'" />!'

## テスティングフレームワークが使用するデータベースの設定の変更（Oracleのみ）
if [ ${DATABASE_TYPE} = 'oracle' ]; then
    perl -0777 -wpi -e 's!\s*<\!--\s* <import file="nablarch/test/test-db-info-oracle.xml"/>\s*-->!\n    <import file="nablarch/test/test-db-info-oracle.xml"/>!' src/test/resources/unit-test.xml

    perl -0777 -wpi -e 's!(\s*<component name="dbInfo" class="nablarch.test.core.db.GenericJdbcDbInfo">.+?</component>)!\n  <\!--$1\n  -->!s' src/test/resources/unit-test.xml
fi
```

このスクリプトは、以下の内容を行います。

- JDBCドライバの依存関係を変更
- gsp-dba-maven-pluginの接続プロパティを変更
- データベースへの接続パラメーターを変更
- ダイアレクトの変更
- （Oracleの場合のみ）テスティングフレームワークが使用するデータベース設定の変更
  - [unit-test.xml (src/test/resources)](https://nablarch.github.io/docs/6u2/doc/application_framework/application_framework/blank_project/CustomizeDB.html#unit-test-xml-src-test-resources)

見てのとおり、単純な文字列置換を行うので最初の1回だけ使うことを想定しています。

実行は、カレントディレクトリに`pom.xml`が存在する状態で行います。

シェルスクリプトの先頭には、使用するデータベースに合わせて設定する項目を並べています。今回の場合は以下のように変更します。

```shell
DATABASE_TYPE=postgresql
DIALECT_CLASS=nablarch.core.db.dialect.PostgreSQLDialect
DRIVER_CLASS=org.postgresql.Driver
JDBC_URL=jdbc:postgresql://localhost:5432/web_db

DRIVER_DEPENDENCY_GROUP_ID=org.postgresql
DRIVER_DEPENDENCY_ARTIFACT_ID=postgresql
DRIVER_DEPENDENCY_VERSION=42.7.4

DB_USER=web_user
DB_PASSWORD=web_password
SCHEMA_NAME=public
DB_ADMIN_USER=${DB_USER}
DB_ADMIN_PASSWORD=${DB_PASSWORD}
```

あとは実行権限を与えてシェルスクリプトを実行します。

```shell
$ chmod a+x /path/to/switch-nablarch-database.sh
$ /path/to/switch-nablarch-database.sh
```

確認してみましょう。

gsp-dba-maven-pluginの実行。

```shell
$ export MAVEN_OPTS='--add-opens java.base/java.lang=ALL-UNNAMED'
$ mvn -P gsp generate-resources
```

参考）

https://nablarch.github.io/docs/6u2/doc/application_framework/application_framework/blank_project/addin_gsp.html

スキーマのエクスポートに失敗しました…。

```shell
[ERROR] Failed to execute goal jp.co.tis.gsp:gsp-dba-maven-plugin:5.1.0:export-schema (default-cli) on project hello-nablarch-web: データのExportに失敗しました。 : スキーマエクスポート実行中にエラー: Cannot run program "pg_dump": error=2, そのようなファイル やディレクトリはありません -> [Help 1]
```

今回はPostgreSQLを直接インストールせず、Dockerで起動していますからね。

`export-schema`は除外することにします。

```xml
    <!-- gsp-dba-plugin -->
    <profile>
      <id>gsp</id>
      <activation>
      </activation>
      <build>
        <directory>${dba.gsp-target-dir}</directory>
        <plugins>
          <plugin>
            <groupId>jp.co.tis.gsp</groupId>
            <artifactId>gsp-dba-maven-plugin</artifactId>
            <executions>
              <execution>
                <id>default-cli</id>
                <phase>generate-resources</phase>
                <goals>
                  <goal>generate-ddl</goal>
                  <goal>execute-ddl</goal>
                  <goal>generate-entity</goal>
                  <goal>load-data</goal>
                  <!-- <goal>export-schema</goal>  -->
                </goals>
              </execution>
            </executions>
```

気を取り直してもう1度。

```shell
$ mvn -P gsp generate-resources
```

今度は成功しました。

```shell
[INFO] --- gsp-dba:5.1.0:generate-ddl (default-cli) @ hello-nablarch-web ---
[WARNING] 1 problem was encountered while building the effective model for org.seasar.container:s2jdbc-gen:jar:2.4.46 during dependency collection step for plugin (use -X to see details)
[INFO]
[INFO] --- gsp-dba:5.1.0:execute-ddl (default-cli) @ hello-nablarch-web ---
ALTER TABLE public.code_name DROP CONSTRAINT code_name_code_id_code_value_fkey
DROP TABLE public.user_session
DROP TABLE public.code_pattern
DROP TABLE public.code_name
[INFO] 51 of 51 SQL statements executed successfully
[INFO]
[INFO] --- gsp-dba:5.1.0:generate-entity (default-cli) @ hello-nablarch-web ---
10月 04, 2024 7:11:17 午後 org.seasar.framework.log.Logger log
情報: バージョン : S2JDBC-Gen 2.4.46
10月 04, 2024 7:11:17 午後 org.seasar.framework.log.Logger log
情報: s2-frameworkのバージョンは2.4.46です。
10月 04, 2024 7:11:17 午後 org.seasar.framework.log.Logger log
情報: s2-extensionのバージョンは2.4.46です。
10月 04, 2024 7:11:17 午後 org.seasar.framework.log.Logger log
情報: s2-tigerのバージョンは2.4.46です。
10月 04, 2024 7:11:18 午後 org.seasar.framework.log.Logger log
警告: ルートパッケージ(com.example)に対応するリソースがクラスパスから見つかりませんでした。
10月 04, 2024 7:11:18 午後 org.seasar.framework.log.Logger info
情報: Running on [ENV]ut, [DEPLOY MODE]Normal Mode
[INFO]
[INFO] --- gsp-dba:5.1.0:load-data (default-cli) @ hello-nablarch-web ---
[INFO] 取込を開始します:CODE_PATTERN.csv
[INFO] 取込を開始します:CODE_NAME.csv
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
```

確認しておきます。

```shell
$ docker container exec -it postgres psql -U web_user web_db
psql (16.4 (Debian 16.4-1.pgdg120+1))
Type "help" for help.

web_db=#
```

作成されたテーブル、登録されたデータを確認します。

```sql
web_db=# \d
            List of relations
 Schema |     Name     | Type  |  Owner
--------+--------------+-------+----------
 public | code_name    | table | web_user
 public | code_pattern | table | web_user
 public | user_session | table | web_user
(3 rows)

web_db=# select * from code_name;
 code_id  | code_value | lang | sort_order | code_name  | short_name | option01 | option02 | option03 | option04 | option05 | option06 | option07 | option08 | option09 | option10
----------+------------+------+------------+------------+------------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------
 C0000001 | 0          | ja   |          1 | アンロック | アンロック | -        |          |          |          |          |          |          |          |          |
 C0000001 | 1          | ja   |          2 | ロック     | ロック     | -        |          |          |          |          |          |          |          |          |
(2 rows)
```

大丈夫そうです。

あとは疎通確認用のアプリケーションを動かします。

```shell
mvn jetty:run
```

`http://localhost:9080`にアクセスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/75744635-c015-601c-0de7-238669a98a45.png)

OKですね。

最初の1回しか使えませんが、これでよいのではないでしょうか。

# 差分

最後に、もうひとつブランクプロジェクトを作成して差分を表示しておきましょう。

```shell
$ mvn archetype:generate \
  -DinteractiveMode=false \
  -DarchetypeGroupId=com.nablarch.archetype \
  -DarchetypeArtifactId=nablarch-web-archetype \
  -DarchetypeVersion=6u2 \
  -DgroupId=com.example \
  -DartifactId=hello-nablarch-web \
  -Dversion=0.0.1 \
  -Dpackage=com.example
$ mv hello-nablarch-web hello-nablarch-web-a


$ mvn archetype:generate \
  -DinteractiveMode=false \
  -DarchetypeGroupId=com.nablarch.archetype \
  -DarchetypeArtifactId=nablarch-web-archetype \
  -DarchetypeVersion=6u2 \
  -DgroupId=com.example \
  -DartifactId=hello-nablarch-web \
  -Dversion=0.0.1 \
  -Dpackage=com.example
$ mv hello-nablarch-web hello-nablarch-web-b
```

ここで、`hello-nablarch-web-a`のみデータベースを切り替えるスクリプトを実行します。  
※ gsp-dba-maven-pluginの`export-schema`の除外は行っていません

差分はこうなりました。

```shell
$ diff -r hello-nablarch-web-a hello-nablarch-web-b
diff -r hello-nablarch-web-a/pom.xml hello-nablarch-web-b/pom.xml
46,52c46,52
<     <nablarch.db.jdbcDriver>org.postgresql.Driver</nablarch.db.jdbcDriver>
<     <nablarch.db.url>jdbc:postgresql://localhost:5432/web_db</nablarch.db.url>
<     <nablarch.db.adminUser>web_user</nablarch.db.adminUser>
<     <nablarch.db.adminPassword>web_password</nablarch.db.adminPassword>
<     <nablarch.db.user>web_user</nablarch.db.user>
<     <nablarch.db.password>web_password</nablarch.db.password>
<     <nablarch.db.schema>public</nablarch.db.schema>
---
>     <nablarch.db.jdbcDriver>org.h2.Driver</nablarch.db.jdbcDriver>
>     <nablarch.db.url>jdbc:h2:./h2/db/SAMPLE</nablarch.db.url>
>     <nablarch.db.adminUser>SAMPLE</nablarch.db.adminUser>
>     <nablarch.db.adminPassword>SAMPLE</nablarch.db.adminPassword>
>     <nablarch.db.user>SAMPLE</nablarch.db.user>
>     <nablarch.db.password>SAMPLE</nablarch.db.password>
>     <nablarch.db.schema>PUBLIC</nablarch.db.schema>
78,83c78,83
<      <dependency>
<        <groupId>org.postgresql</groupId>
<        <artifactId>postgresql</artifactId>
<        <version>42.7.4</version>
<        <scope>runtime</scope>
<      </dependency>
---
>         <dependency>
>           <groupId>com.h2database</groupId>
>           <artifactId>h2</artifactId>
>           <version>2.2.220</version>
>           <scope>runtime</scope>
>         </dependency>
120c120
<         <nablarch.db.schema>public</nablarch.db.schema>
---
>         <nablarch.db.schema>PUBLIC</nablarch.db.schema>
141,146c141,146
<      <dependency>
<        <groupId>org.postgresql</groupId>
<        <artifactId>postgresql</artifactId>
<        <version>42.7.4</version>
<        <scope>runtime</scope>
<      </dependency>
---
>               <dependency>
>                 <groupId>com.h2database</groupId>
>                 <artifactId>h2</artifactId>
>                 <version>2.2.220</version>
>                 <scope>runtime</scope>
>               </dependency>
179,184c179,184
<      <dependency>
<        <groupId>org.postgresql</groupId>
<        <artifactId>postgresql</artifactId>
<        <version>42.7.4</version>
<        <scope>runtime</scope>
<      </dependency>
---
>               <dependency>
>                 <groupId>com.h2database</groupId>
>                 <artifactId>h2</artifactId>
>                 <version>2.2.220</version>
>                 <scope>runtime</scope>
>               </dependency>
diff -r hello-nablarch-web-a/src/env/dev/resources/env.properties hello-nablarch-web-b/src/env/dev/resources/env.properties
6c6
< nablarch.db.jdbcDriver=org.postgresql.Driver
---
> nablarch.db.jdbcDriver=org.h2.Driver
10c10
< nablarch.db.url=jdbc:postgresql://localhost:5432/web_db
---
> nablarch.db.url=jdbc:h2:./h2/db/SAMPLE
14c14
< nablarch.db.user=web_user
---
> nablarch.db.user=SAMPLE
18c18
< nablarch.db.password=web_password
---
> nablarch.db.password=SAMPLE
22c22
< nablarch.db.schema=public
---
> nablarch.db.schema=PUBLIC
diff -r hello-nablarch-web-a/src/main/resources/web-component-configuration.xml hello-nablarch-web-b/src/main/resources/web-component-configuration.xml
102c102
<   <component name="dialect" class="nablarch.core.db.dialect.PostgreSQLDialect" />
---
>   <component name="dialect" class="nablarch.core.db.dialect.H2Dialect" />
```