【SAP BTP】CAP Service SDK for JavaでOData APIを作ってみる(1)

# はじめに

[CAP(SAP Cloud Application Programming Model)](https://cap.cloud.sap/docs/)を利用してBTP環境にデプロイするODataAPIを作ってみます。

以前にも一度試しているものの、WebIDEベースの開発であり、最近では使えないこともあるのでBusiness Application Studioで実施しました。
今回の手順だとVSCodeなどのローカル開発環境でもほぼ同様に作れると思います。
[SAP CP Trial環境でMulti Target Applicationを作ってみる【ODataService_V2の作成】](https://qiita.com/yonekura-h/items/62abe8b4ff1a747bd2e9)

BTPでのJava開発には[SAP Cloud SDK](https://sap.github.io/cloud-sdk/docs/overview/overview-cloud-sdk)もあり、CAPプロジェクトとの統合も可能です。
SAP Cloud SDKにはJavaアプリケーションにおけるODataクライアントはあるものの、OData APIとしてサービスを公開する機能はなさそうでした。
より多くの機能が必要となる場合は導入を検討する必要がありそうです。
[SAP Cloud SDKとCAPの違い](https://sap.github.io/cloud-sdk/docs/related-projects/cloud-application-model)

利用しているBTP、Business Application Studio（BAS）はすべてTrial環境です

【つづき】
[【SAP BTP】CAP Service SDK for JavaでOData APIを作ってみる(2)](https://qiita.com/yonekura-h/items/9ce04ddbb37dc9001bb4)


# 準備

※Trial環境のサブアカウントにSpace「dev」が作成されていること前提

## BASのDev Space作成
まずはTrial環境のBASへアクセスし、Dev Spaceを作成します。
作成する際に「Full Stack Cloud Application」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/cc8306cf-97b7-cae4-5638-19f846f7b5ea.png)


## HANA DBインスタンス作成
Javaアプリケーションを作り始める前に接続するHANA DB(HDIConteiner)のインスタンスを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/613b3c27-f485-b735-c782-9ab1aa7d30d5.png)

「SAP HANA Schemas & HDI Containers Trial」をCreateします。
デフォルトのパラメータは変更せず、Instance Nameは任意です。
「demoShared」の名称で作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/7b207ffd-d977-f675-5d5c-bd44af9acdfd.png)


作成が終わったら「Instances and Subscriptions」で確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/fe33b25b-3136-c02f-122c-d0d2faf8f356.png)


# Javaアプリケーション開発

環境の準備が終わったらBASで作成したFull Stackのスペースに移動してJavaアプリケーションを作り始めます。

## MTAプロジェクト作成

今回はMTAとしてJavaアプリケーションをデプロイしていくので、最初にMTAプロジェクトを作成します。
Welcomeページから「Start From Template」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/a5489975-91ac-6da9-2148-d7153d46a800.png)
「Basic Multitarget Application」を選択し、プロジェクト名を指定してMTAを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/90edf4aa-8ea3-5e62-b94e-b095ed5ae3f5.png)

出来上がったMTAのプロジェクトにはmta.yaml(とgitignore)のみが含まれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/4578817e-992a-4a54-7a2b-8c054e9e3b52.png)




## CAPプロジェクトの作成

CAPプロジェクトの作成はドキュメントの[Getting Started](https://cap.cloud.sap/docs/java/getting-started)を参考に進めていきます。
作成したMTAプロジェクトに移動し、Mavenコマンドを実行します。
```
$ mvn archetype:generate -DarchetypeArtifactId="cds-services-archetype" -DarchetypeGroupId="com.sap.cds" -DarchetypeVersion="RELEASE" "-DinteractiveMode=true"
```

> BASのターミナルでドキュメントのままコマンドをたたくとgroup ID等を聞かれないので、
> "-DinteractiveMode=true"を追加します。

group ID、artifact ID等を入力する必要があるので、任意の値を指定します。
今回は以下の設定としました。

| 内容 | 値 |
|:-:|:-:|
| groupId:  |  jp.co.kyoso.demo |
| artifactId: | capdemoservice  |
| package:  |  ※デフォルト |

成功するとMTA内にプロジェクトが生成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/9a8b60bd-f58e-dcda-6d0b-056605d02bdb.png)


## サンプル
生成したCAPプロジェクトにはアプリケーションの中身が存在しません。
まずはテスト実行、Deploy、DB接続等を理解するためにサンプルのアプリケーションを生成します。

※サンプルを利用せずODataサービス開発をする場合の方法は以下に記載しているので参照ください。
[【SAP BTP】CAP Service SDK for JavaでOData APIを作ってみる(2)](https://qiita.com/yonekura-h/items/9ce04ddbb37dc9001bb4)

CAPプロジェクトのディレクトリに移動して以下のコマンドを実行します。
```
$ cd capdemoservice/
$ mvn com.sap.cds:cds-maven-plugin:addSample
```
中身が増えました。
それぞれの内容に関しては[公式ドキュメント](https://cap.cloud.sap/docs/java/getting-started#project-layout)を参照してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/e22e4565-0e3c-8ae1-ef96-a6dde15f3de2.png)

## テスト実行
上記まで終えたらローカルで実行してみます。
```
$ mvn spring-boot:run
```

localhost:8080で実行された内容を確認すると、サービスが起動しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/bde716f7-0483-9622-0e33-edae5e1d0e83.png)

Booksエンティティ（/odata/v4/CatalogService/Books）へアクセスするとデータが表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/12e4b524-8755-dc47-e1f0-7a01c2ee5bac.png)

ローカルのテスト実行の場合はdb/data/my.bookshop-Books.csvのデータが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/a257aa00-b6ad-b836-ece7-e6d1522a08d9.png)

## BTPへDeploy
CAPによるODataAPIの実行が確認できたので、一度BTP環境へデプロイしてみます。
MTAとしてDeployをするために `mta.yaml` ファイルに追加したJavaアプリケーションを記載します。

```mta.yaml
_schema-version: "3.2"
ID: mtademo
version: 0.0.1

# JavaModuleを追加
modules:
  - name: capdemo_api
    type: java
    path: capdemoservice
    parameters:
      buildpack: java_buildpack
    properties:
      SPRING_PROFILES_ACTIVE: cloud
    build-parameters:
      builder: custom
      commands: [ mvn clean package ]
      build-result: "srv/target/*-exec.[wj]ar"
    provides:
      - name: srv-api # required by consumers of CAP services (e.g. approuter)
        properties:
          srv-url: ${default-url}
```

MTAプロジェクトのルートディレクトリでmbt buildコマンドを実行します。
```
$ mbt build
```

成功すると `mta_archives/` ディレクトリが作成され、配下に.mtarファイルが生成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/149c0bd6-e083-7fc3-370f-2cd8eedafffa.png)

DeployにはCF CLIを用います。
 `cf login` でTrial環境へログインします。
```
$ cf login
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/7cc19cf4-1223-8e1f-9338-31f29ff845c0.png)


ログイン出来たら `cf deploy` で先ほど作成した.mtarファイルをデプロイします。
```
cf deploy mta_archives/mtademo_0.0.1.mtar 
```
 `Process finished.` が表示されていれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/c4b2f82f-45c0-d31e-dba9-a020103dac59.png)


devスペースのApplicationsでデプロイしたJavaアプリケーションを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/336399ab-917b-efec-ea14-040363037045.png)

アプリケーションにアクセスすると動作していることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/2fd6709c-4f40-4eba-6b28-719eccdf3595.png)

ただし、Booksエンティティ（/odata/v4/CatalogService/Books）にデータは表示されていません。
DBと接続していないので中身が空です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/e1988a33-3e66-a41d-74fd-098b6ba81ad4.png)

## DBとの接続
### mta.yamlを編集

CAPの接続先DBはデフォルトだとService Bindingが定義されているDBとなります。
そのため `mta.yaml` ファイルを編集し、Javaアプリケーション(capdemo_api)と準備段階で作成したHANA DBのインスタンスにBindingを定義します
 `mta.yaml` ファイルに以下を追記します
```mta.yaml
_schema-version: "3.2"
ID: mtademo
version: 0.0.1

# JavaModule
modules:
  - name: capdemo_api
    type: java
    path: capdemoservice
    parameters:
      buildpack: java_buildpack
    properties:
      SPRING_PROFILES_ACTIVE: cloud
    build-parameters:
      builder: custom
      commands: [ mvn clean package ]
      build-result: "srv/target/*-exec.[wj]ar"
    provides:
      - name: srv-api # required by consumers of CAP services (e.g. approuter)
        properties:
          srv-url: ${default-url}
    # resources -> useDemoSharedをJavaModuleに追加
    requires:
     - name: useDemoShared
       properties:
          JBP_CONFIG_RESOURCE_CONFIGURATION: '[tomcat/webapps/ROOT/META-INF/context.xml:
             {"service_name_for_DefaultDB" : "~{hdi-container-name}"}]'
resources:
  # 作成済みのHANA DBサービスをresourcesに記載
  - name: useDemoShared
    parameters:
      service-name: demoShared
      service: hanatrial
      service-plan: securestore
      config:
        schema: sampleSchema
    properties:
      hdi-container-name: '${service-name}'
    type: org.cloudfoundry.existing-service
```

もう一度MTAをBuildしてデプロイを実行します。
```
$ mbt build
$ cf deploy mta_archives/mtademo_0.0.1.mtar
```

### HANA DBにテーブル追加

APIを実行する前にCDSに定義されているデータ構造をHANA DBに作成します。
HANA DBへのアクセスはBASの「SAP HANA Database Explorer」を使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/d05f7f5f-06cc-6ca7-3257-fabbd74214d2.png)
※「SAP HANA Database Explorer」へアクセスするためのパラメータはHANA DBとJavaアプリケーションのBinding情報から拾うことができます

以下のSQLでTable / Viewを作成します。
(Javaプロジェクトのresource/schema.sqlに記載されている内容)

```sql
CREATE TABLE my_bookshop_Books (
  ID INTEGER NOT NULL,
  title NVARCHAR(5000),
  stock INTEGER,
  PRIMARY KEY(ID)
);

CREATE VIEW CatalogService_Books AS SELECT
  Books_0.ID,
  Books_0.title,
  Books_0.stock
FROM my_bookshop_Books AS Books_0;
```

テーブルを作成して以下のデータを登録しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/eec1954e-0f60-3a39-bbea-470c0a466fcf.png)

更新されたJavaのODataAPIを実行すると、無事にDBへ登録した値が取得できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/e9800dbf-43ef-c257-1b9b-27f784ed021c.png)

# 追記（2022/07）
改めて上記の手順でCAPプロジェクトを作成したところ、HANA DBとのBindingを設定してもデプロイしたODataAPIがDBにアクセスできていない状況を確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/89d9c1f9-8c52-2bf5-4a9b-3ed757ffdfc4.png)

暫定の対処としては ` pom.xml` に記載されている `cds.services.version` のバージョンを下げることで
今回は1.26.0 → 1.24.0に下げることでデータが取得できること確認しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159467/2e558911-2b31-8133-dea4-c3a4d270a55f.png)

※※※
1.26.0以上の場合、[CloudFoundryターゲットプラットフォームを追加する](https://cap.cloud.sap/docs/java/getting-started#add-cloudfoundry-target-platform)対応が必要なのだと思いますが、こちらを実行した場合はBooksエンティティへのアクセス時にBasic認証が求められますが通りません。。
認証をパスするもしくは回避する方法がわかり次第、追記します
※※※


# おわりに
CAP Service SDK for Javaを使ってODataAPIが構築できることが確認できました。
今回はSampleプロジェクトを使うのみだったので、次は実際サービス開発を進めていきたいと思います。