SAP CP Integration Serviceでメッセージ編集とかHTTPリクエストとかをやってみた

#はじめに

この記事は[「SAP S/4HANAで購買発注が登録されるたびiPhoneに「アイーン」とPush通知が来たらぜったいどきどきしちゃう」シリーズ](https://qiita.com/monamona/items/0e4c38ce315282e73b96)の4つ目(最終回！)の記事です。

## 前回までの実装

前回までの記事では、「SAP S/4HANAで伝票登録されたら「あい〜〜ん」Push通知が来たらぜったいどきどきしちゃう」という奇特な業務ユーザからの要望をかなえるべくいろいろとがんばってきました。

今回はこれまでの実装を総括して、**SAP S/4HANAで購買発注が登録されたらCPI(SAP Cloud Platform Integration Service)のIntegration Flowをトリガーし、Integration Flowから購買発注伝票番号を含むPush通知をiPhoneに送れる**ようにしていきたいと思います。

つまり、ユーザの熱い願いはこの記事を以ってついに実現します！

## 今回の目標

今回の記事のゴールは、SAP S/4HANAで購買発注伝票が登録されたらIDocによってその情報がIntengration Flowに連携され、登録された伝票番号をIntegration Flow内で取得し、Mobile ServiceのPush通知APIを使ってその番号を含む通知をiPhoneに送れるようにすることです。長い……

とはいえこれまでの記事で大部分の実装は完了しており、
あとはIntegration Flowを通じてプロセスを統合していくだけです。

というわけで、この記事では

- Integration FlowからのHTTPリクエスト実行方法（REST API呼出方法）
- Integration Flow内でのパラメータ操作方法
- Integration Flow内でのログ出力方法

などを主に紹介していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/44084fdd-a9e6-4e83-bc48-e436a5d8b49c.png)


# 前提条件

## 開発実行環境
- フロントエンド実行環境: iPhone11 pro iOS 13.3
- フロントエンド開発環境: macOS Mojave 10.14.6 / Xcode 11.3 ※ Apple Developer Account(有料)を取得していること。
- バックエンド開発実行環境: SAP S/4HANA 1809
- クラウド開発実行環境: SAP Cloud Platform (Cloud Foundry trial account) ※ 無料
    - Mobile Services
    - Integration Service

## 事前手順
- [こちらの記事](https://qiita.com/monamona/items/a1b065ca245aa5d8b2be)と同様の手順で、SAP CP Mobile Servicesを活用したPush通知の設定を行ったiOSアプリを構築していること。
- [こちらの記事](https://qiita.com/monamona/items/7ddd673c12205ef51ef4)と同様の手順で、SAP CP Mobile ServicesのPush通知APIの疎通確認ができていること。
- [こちらの記事](https://qiita.com/monamona/items/b13c0eef82f849323b78)と同様の手順で、SAP S/4HANAでの購買発注伝票登録をトリガーにSAP CP Integration SerciceのIntegration Flowを開始できるようになっていること。

# そもそもIntegration Serviceの実装ではなにをどうやって定義するのか

### 何を？

今回の実装でいうと、
- SAP CP MobileへHTTPリクエストを行うための宛先やメソッドなどを設定する
- S/4HANAからIDocで受け取ったメッセージBodyをSAP CP Mobile Servicesに渡したいメッセージBodyに変換する
というFlowを定義することになります。

### どうやって？
Flow内で同じ内容を設定するにしても、設定用の箱を使ってぽちぽちやる方法も、Grooby Scriptとしてコーディングする方法もあるようです。
Flowの編集画面を見るとさまざまな設定用の箱が用意されていてすぐに全部マスターするのは難しそうだったので、今回はとりあえずGroovyで書けそうな部分はなるべく書いてしまい、そこでやりづらいなと思ったことだけ設定用の箱をぽちぽちして設定するという戦略にしました（Groovyはオープンな言語なので、わからないことがあってもググれば結構なんでもわかるので嬉しい）。

Groovy Scriptを使う場合は、もちろんScript内からIntegration Flowの情報にアクセスする必要があるので、そのための専用のSDKをインポートし、SDKのメソッドを使ってFlow関連情報を編集していきます。

### リファレンス

- [公式のHelpのこの辺り](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/317179576dbb460d991b61f4e315b975.html)にIntegration Flowの定義方法について比較的具体的に書いてあります。
- [SDKのJava Doc](https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/c5c7933b77ba46dbaa9a2c1576dbb381.html)が用意されており、Groovy Scriptを書く際に参考にすることができます。
- これが一番役にたつと思うのですが、Integration Serviceには最初から実装済のパッケージが入っています。これの中身を見るのが初心者的にはわかりやすいかなと思いました。わたしが見てよかったなと思ったパッケージの名称は下記です。
    - `Cloud Integration - Exemplars`
    - ` Integration Flow Design Guidelines`
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/d6b94aef-1b2a-772f-4522-ec4a798ea279.png)

# 構築手順
前回の記事ですでにIntegration Flowを作成していると思うので、これを改修していきます。

## 概要

下記のようなフローを作っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/9ebda452-b65a-20cf-fb3b-7af2180224e2.png)

ただし、上記で"log_a", "log_b", "log_c", "log_d"と書いてある箱は、実装の便宜のために付け加えたログ出力用の箱であり、機能には関係ありません。

重要なのは、IDoc --> "convert xml to json" --> "set http header" --> "modify body" --> HTTPという処理の流れです。

それぞれの箱の設定内容の概要を下記に示します。

|名称                   |タイプ                  | 設定内容概要                            | 
|:---------------------|:---------------------|:---------------------------------------|
| IDOC                 | IDOC                 |Integration Flowのエンドポイントなどを定義　   |
| log_x                | Groovy Script        |ログ出力処理を定義　　　　　　　　            |
| convert xml to json  | XML to JSON Converter|IDOCのメッセージBodyをJSONに変換             |
| set http header      | Content Modifier     | Push通知APIを呼び出すためのHeader情報を定義  |
| modify body          | Groovy Script        | Push通知APIに渡すBody情報を編集            |
| HTTP                 | HTTP                 | Push通知APIのエンドポイントや呼出メソッドなどを定義|


それでは以下で設定の詳細を見てきます。

## HTTPリクエスト関連の基本設定

### ヘッダ情報設定

|名称                   |タイプ                  | 設定内容概要                            | 
|:---------------------|:---------------------|:---------------------------------------|
| set http header      | Content Modifier     | Push通知APIを呼び出すためのHeader情報を定義  |

Content Modifierというタイプの箱を使って、メッセージのヘッダ（Push通知APIを叩く際のHTTPリクエストヘッダ）を設定します。
ヘッダに設定したい内容は前回の記事でAPIの動作確認をしたのでわかっています。

だいたいこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/9c25e80d-8914-a77f-e0c8-62b04977d0be.png)

この箱を使ってMessage Bodyを設定することもできるはずなのですが、伝票番号を抽出してAPIに渡すためにはGroovy Scriptを使った方が簡単そうだったので、この段階ではBodyの欄にはなにも設定しないことにしました。

### 認証情報設定

Security Materialというものを作成しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/985c4585-fa62-5bc2-32ea-8a86ed3c3c0c.png)

画面右上の"Add"ボタンから"Add User Credential"を選択し、Cloud Foundryログイン時のメールアドレスとパスワードを入力して"Deploy"するだけでOKです。

この時につけた名称（今回の場合は`MOBILE_USER`）を、次の手順で参照します。

### メソッド・アドレス設定

|名称                   |タイプ                  | 設定内容概要                            | 
|:---------------------|:---------------------|:---------------------------------------|
| HTTP                 | HTTP                 | Push通知APIのエンドポイントや呼出メソッドなどを定義|

メッセージの宛先関連の情報は一番右の矢印"HTTP"の部分で設定します。
これも普通に、Push通知APIを叩くために必要なAddressやMethodを粛々と設定します。
Credential Nameでは先ほどデプロイしたSecurity Materialの名称を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/4e1db012-c22e-cddf-3830-34cf5c121142.png)

## Integration Flow内のメッセージ編集

### Integration Flowログ出力

|名称                   |タイプ                  | 設定内容概要                            | 
|:---------------------|:---------------------|:---------------------------------------|
| log_x                | Groovy Script        |ログ出力処理を定義　　　　　　　　            |

メッセージを編集するにあたって、編集する対象のメッセージがなにであるかわからないのはつらいので、ログを吐かせるようにしておきます。
Groovy Scriptというタイプの箱を用いてスクリプトを書きます。

```groovy
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
    def body = message.getBody(java.lang.String) as String;
    def messageLog = messageLogFactory.getMessageLog(message);
    if(messageLog != null){
        messageLog.setStringProperty("Logging#1", "Printing Payload As Attachment")
        messageLog.addAttachmentAsString("log_a:", body, "text/plain"); //"log_a"のところで適宜ログに名前を付ける
     }
    return message;
}
```

こうすることで、Integration Flowをトリガーした時にログが吐かれ、メッセージのBodyの中身を好きなタイミングで確かめることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/845cdcef-4305-1ac0-2240-141daedc7bf5.png)

### Bodyの設定（伝票番号を取得してBodyに渡す）

#### XMLからJSONに変換("convert xml to json")

|名称                   |タイプ                  | 設定内容概要                            | 
|:---------------------|:---------------------|:---------------------------------------|
| convert xml to json  | XML to JSON Converter|IDOCのメッセージBodyをJSONに変換             |

伝票番号を含んでいるIDOCからの情報はxml形式で来るのですが、JSONの方が（たぶん）扱いやすいと思ったので変換します。

このためにXML to JSON Converterというタイプの箱を用います。
設定内容は簡単で、たぶんデフォルトから特に中身を変更する必要はないと思います。
<img width="400" alt="スクリーンショット 2020-02-11 21.31.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/a837ab9e-4d70-ba11-47d4-13dcb3bf594e.png">

#### 伝票番号を取得してメッセージBodyに設定

|名称                   |タイプ                  | 設定内容概要                            | 
|:---------------------|:---------------------|:---------------------------------------|
| modify body          | Groovy Script        | Push通知APIに渡すBody情報を編集            |

IDocから連携されたメッセージBodyから伝票番号だけ抜き出して、これを元に新しいメッセージBodyテキストを作成し、メッセージBodyとして更新します。
この新しいメッセージBodyが、最後のHTTPリクエストでPush通知APIを叩くときに使われることになります。

Groovy Scriptというタイプの箱を用いて、スクリプトを書いていきます。

```groovy
import groovy.json.*
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;

def Message processData(Message message) {
		
    //IDocから渡されたメッセージBodyを取得
	def stringBody = message.getBody(java.lang.String) as String;
    def sluper = new JsonSlurper();
    def object = sluper.parseText(stringBody);
    def json = new JsonBuilder();

    //伝票番号を取得
    def DocNo = json(object).ORDERS05.IDOC.E1EDK01.BELNR;

    //伝票番号を用いて新しいBody内容を定義
    def newBody = $/
    {
        "alert": "{\"title\": \"あい〜〜〜〜〜ん\",\"body\" : \"ドリフ大爆笑DVDの購買発注伝票(${DocNo})が登録されました！\"}",
        "badge": 1,
        "sound": "sumikko_aiiiin.aiff"
    }
    /$.toString();

    //新しいBody内容をセット
    message.setBody(newBody);

	return message;
}
```

## 動作確認
以上の設定が済んだらIntegration Flowをデプロイし直し、満を持して購買発注伝票をSAP S/4HANAで登録してみましょう！！！

あい〜〜〜ん
<img width="375" alt="IMG_0363.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/6cbffd16-6a9d-5d01-30ec-a37a705afbaf.png">


# おめでとうございます！

ついにSAP S/4HANAで購買発注が登録されるたびiPhoneに「アイーン」とPush通知が来るようになりました！
誰かがSAP S/4HANAで伝票登録するたびに通知がきちゃうなんてなんだかどきどきしちゃいますね。

このアプリケーションを活用して、ぜひ甘酸っぱくもほろ苦いSAPライフをお楽しみください！