[Google Drive API v3] Javaでファイル、ユーザー情報の変更通知(サブスクライブ)を受信・停止する

Google Drive API v3（Java）を使用して、
ファイル、ユーザー情報の変更通知(サブスクライブ)を受信・停止する方法
についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Drive API v3] JavaでDrive APIを使う](https://qiita.com/doran/items/15b2c59adb410ddeeb8a)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[ファイルの変更を受信](#1-ファイルの変更を受信)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|
|2||[ユーザー情報の変更を受信](#2-ユーザー情報の変更を受信)|
||1|[スコープ](#21-スコープ)|
||2|[実行](#22-実行)|
||3|[レスポンスの内容](#23-レスポンスの内容)|
|3||[変更通知を停止](#3-変更通知を停止)|
||1|[スコープ](#31-スコープ)|
||2|[実行](#32-実行)|
||3|[レスポンスの内容](#33-レスポンスの内容)|
|4||[変更通知を受け取る](#4-変更通知を受け取る)|
||1|[通知ヘッダ](#41-通知ヘッダ)|

## 1. ファイルの変更を受信
指定したファイルが変更された場合に通知を受け取るようにします。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
DriveScopes.DRIVE
DriveScopes.DRIVE_APPDATA
DriveScopes.DRIVE_FILE
DriveScopes.DRIVE_METADATA
DriveScopes.DRIVE_METADATA_READONLY
DriveScopes.DRIVE_PHOTOS_READONLY
DriveScopes.DRIVE_READONLY
```
[⧉[Google Drive API v3] JavaでDrive APIを使う(2.2 Driveインスタンスを取得)](https://qiita.com/doran/items/15b2c59adb410ddeeb8a#22-driveインスタンスを取得)
でスコープを指定してください。
### 1.2. 実行
監視したいファイルのIDを指定します。
レスポンスの**id**と**resourceId**は削除時に必要になります。

```java
public static void main(String[] args) throws Exception{
    Drive drive = getDrive();
    Drive.Files files = drive.files();

    Channel channel = new Channel();
    channel.setAddress("通知を受け取るURL");
    Drive.Files.Watch watch = files.watch("ファイルID", channel);
    
    Channel res = watch.execute();
    System.out.println(res);
}
```
#### 1.2.1. HTTPリクエスト
POST:　https:\//www.googleapis.com/drive/v3/drives
が実行されます。

#### 1.2.2. クエリパラメータ
Drive.Files.Watchのsetメソッドにより、クエリパラメータを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setSupportsAllDrives|Boolean|要求元のアプリケーションがマイドライブと共有ドライブの両方をサポートしているか|
|setAcknowledgeAbuse|Boolean|ユーザーが既知のマルウェアまたはその他の不正なファイルをダウンロードするリスクを認識しているか|

#### 1.2.3. リクエストボディ
Channelのsetメソッドにより、リクエストボディを設定できます。

|メソッド|引数|説明|
|---|---|---|
|setAddress|String|このチャネルの通知が配信されるアドレス|
|setType|String|このチャネルに使用される配信メカニズムのタイプ<br>web_hook、webhook|
|setId|String|チャネルを識別するUUID|
|setPayload|Boolean|ペイロードが必要か|
|setResourceId|String|このチャネルで監視されているリソースを識別するID|
|setResourceUri|String|監視対象リソースのバージョン固有の識別子|
|setToken|string|このチャネル経由で配信される各通知とともにターゲットアドレスに配信される任意の文字列|
|setExpiration|Long|通知チャネルの有効期限の日付と時刻(Unixタイムスタンプ ミリ秒単位)|
|setParams|Map\<String,String\>|配信チャネルの動作を制御する追加パラメータ|

#### 1.3. レスポンスの内容

#### Channel

|メソッド|戻り値|説明|
|---|---|---|
|getKind|String|リソースの種類<br>固定文字列："api#channel"|
|getPayload|Boolean|ペイロードが必要か|
|getId|String|このチャネルを識別するUUID|
|getResourceId|String|このチャネルで監視されているリソースを識別するID|
|getResourceUri|String|監視対象リソースのバージョン固有の識別子|
|getToken|String|このチャネル経由で配信される各通知とともにターゲットアドレスに配信される任意の文字列|
|getExpiration|Long|通知チャネルの有効期限の日付と時刻(Unixタイムスタンプ ミリ秒単位)|
|getType|String|このチャネルに使用される配信メカニズムのタイプ<br>web_hook、webhook|
|getAddress|String|このチャネルの通知が配信されるアドレス|
|getParams|Map\<String,String\>|配信チャネルの動作を制御する追加パラメータ|

## 2. ユーザー情報の変更を受信
指定したユーザーの情報が変更された場合に通知を受け取るようにします。

### 2.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
DriveScopes.DRIVE
DriveScopes.DRIVE_APPDATA
DriveScopes.DRIVE_FILE
DriveScopes.DRIVE_METADATA
DriveScopes.DRIVE_METADATA_READONLY
DriveScopes.DRIVE_PHOTOS_READONLY
DriveScopes.DRIVE_READONLY
```
[⧉[Google Drive API v3] JavaでDrive APIを使う(2.2 Driveインスタンスを取得)](https://qiita.com/doran/items/15b2c59adb410ddeeb8a#22-driveインスタンスを取得)
でスコープを指定してください。
### 2.2. 実行
監視したいファイルのIDを指定します。
レスポンスの**id**と**resourceId**は削除時に必要になります。

指定するページトークンIDの取得方法は、
[⧉[Google Drive API v3] Javaでユーザーや共有ドライブ、ファイルの変更履歴を取得する](https://qiita.com/doran/items/aca4993ba3cebff2c3af#1-変更履歴の開始トークンを取得)
こちらの記事を参照してください。

```java
public static void main(String[] args) throws Exception{
    Drive drive = getDrive();
    Drive.Changes changes = drive.changes();

    Channel channel = new Channel();
    channel.setAddress("通知を受け取るURL");
    Drive.Changes.Watch watch = changes.watch("ページトークンID", channel);
    
    Channel res = watch.execute();
    System.out.println(res);
}
```
#### 2.2.1. HTTPリクエスト
POST:　https:\//www.googleapis.com/drive/v3/changes/watch
が実行されます。

#### 2.2.2. クエリパラメータ
Drive.Changes.Watchのsetメソッドにより、クエリパラメータを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setPageSize|Integer|ページごとに返される変更の最大数|
|setPageToken|String|次のページで前のリスト要求を継続するためのトークン<br>**レスポンスのgetNextPageTokenで取得が可能**|
|setDriveId|String|変更が返される共有ドライブID|
|setIncludeCorpusRemovals|Boolean|変更通知にファイルリソースを含めるか|
|setIncludeItemsFromAllDrives|Boolean|マイドライブと共有ドライブの両方の項目を結果に含めるか|
|setIncludeRemoved|Boolean|削除やアクセスの喪失などによって項目が変更リストから削除されたことを示す変更を含めるか|
|setPageSize|Integer|ページごとに返される変更の最大数|
|setRestrictToMyDrive|Boolean|結果をマイドライブ階層内の変更に制限するか|
|setSpaces|String|コーパス内でクエリするスペースのカンマ区切りのリスト<br>drive、appDataFolder|
|setSupportsAllDrives|Boolean|要求元のアプリケーションがマイドライブと共有ドライブの両方をサポートしているか|

#### 2.2.3. リクエストボディ
Channelのsetメソッドにより、リクエストボディを設定できます。

[1.2.3. リクエストボディ](#123-リクエストボディ)と同じです。

#### 2.3. レスポンスの内容

#### Channel

[1.3. レスポンスの内容](#13-レスポンスの内容)と同じです。

## 3. 変更通知を停止
登録した通知を停止します。

### 3.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
DriveScopes.DRIVE
DriveScopes.DRIVE_APPDATA
DriveScopes.DRIVE_FILE
DriveScopes.DRIVE_METADATA
DriveScopes.DRIVE_METADATA_READONLY
DriveScopes.DRIVE_PHOTOS_READONLY
DriveScopes.DRIVE_READONLY
"https://www.googleapis.com/auth/docs"
"https://www.googleapis.com/auth/drive.apps"
```
[⧉[Google Drive API v3] JavaでDrive APIを使う(2.2 Driveインスタンスを取得)](https://qiita.com/doran/items/15b2c59adb410ddeeb8a#22-driveインスタンスを取得)
でスコープを指定してください。
### 3.2. 実行
停止したい通知のチャネルIDとリソースIDを指定します。
この2つの指定は必須になっています。
2つのIDと一致する通知がない、または既に停止済みの場合は例外が発生します。

```java
public static void main(String[] args) throws Exception{
    Drive drive = getDrive();
    Drive.Channels channels = drive.channels();

    Channel channel = new Channel();
    channel.setId("チャネルID");
    channel.setResourceId("リソースID");

    Drive.Channels.Stop stop = channels.stop(channel);
    stop.execute();
}
```
#### 3.2.1. HTTPリクエスト
POST:　https:\//www.googleapis.com/drive/v3/channels/stop
が実行されます。

#### 3.2.2. クエリパラメータ
クエリパラメータはありません。

#### 3.2.3. リクエストボディ
Channelのsetメソッドにより、リクエストボディを設定できます。

[1.2.3. リクエストボディ](#123-リクエストボディ)と同じです。

#### 3.3. レスポンスの内容

成功した場合は何も返しません。
失敗した場合は例外を出力します。

## 4. 変更通知を受け取る
指定した変更を感知すると、[Channel.setAddress()](#123-リクエストボディ)で登録したアドレス宛に
HTTPS POSTが送信されます。

通知のヘッダには、「X-Goog-」という接頭辞が付きます。
基本的には、本文は空で送られてきますので、ヘッダの内容で変更内容を確認します。
ただし、通知のタイプによっては、メッセージ本文を含めることもできます。

### 4.1. 通知ヘッダ

#### 4.1.1. 必ず含まれるヘッダ
|ヘッダ|内容|
|---|---|
|X-Goog-Channel-ID|この通知チャンネルを識別するために指定した UUID などの一意の文字列|
|X-Goog-Message-Number|この通知チャネルのこのメッセージを識別する整数<br>sync メッセージの場合は常に1となる<br>チャネル上の後続のメッセージ毎に増加するが連続の値ではない|
|X-Goog-Resource-ID|監視対象リソースを識別値|
|X-Goog-Resource-State|[リソースの状態を表す](#リソースの状態)|
|X-Goog-Resource-URI|監視対象リソースのAPIバージョン固有の識別子|

#### リソースの状態

|X-Goog-Resource-State|変更の対象|配信のタイミング|
|---|---|---|
|sync|[ファイル](#1-ファイルの変更を受信)<br>[ユーザー情報](#2-ユーザー情報の変更を受信)|チャネルが作成されました|
|add|[ファイル](#1-ファイルの変更を受信)|リソースが作成または共有されました|
|remove|[ファイル](#1-ファイルの変更を受信)|既存のリソースが削除された<br>または、共有が解除された|
|update|[ファイル](#1-ファイルの変更を受信)|リソースの1つ以上のプロパティ<br>（メタデータ）が更新されました|
|trash|[ファイル](#1-ファイルの変更を受信)|リソースをゴミ箱に移動しました|
|untrash|[ファイル](#1-ファイルの変更を受信)|リソースをゴミ箱から削除しました|
|change|[ユーザー情報](#2-ユーザー情報の変更を受信)|1つ以上の変更履歴項目が追加されました|

#### 4.1.2. 内容によって含まれるヘッダ
|ヘッダ|内容|
|---|---|
|X-Goog-Changed|[変更に関する詳細情報](#変更に関する詳細情報)|
|X-Goog-Channel-Expiration|通知チャンネルの有効期限|
|X-Goog-Channel-Token|アプリによって設定され、通知ソースの検証に使用できる通知チャネルトークン|

#### 変更に関する詳細情報
|変更の種類|内容|
|---|---|
|content|リソースの内容が更新された|
|properties|1 つ以上のリソース プロパティが更新された|
|parents|1 つ以上のリソースの親が追加または削除された|
|children|1 つ以上のリソースの子が追加または削除された|
|permissions|リソースの権限が更新された|


<br>
<br>
おしまい。。