# 通知設計書 9-FileChangesListener通知

## 概要

本ドキュメントは、OpenSearchにおけるFileChangesListener通知の設計仕様を記載する。FileChangesListenerはファイルシステム上のファイル・ディレクトリの作成・変更・削除を検出してリスナーに通知するためのインターフェースである。FileWatcherクラスが定期的にファイルシステムをポーリングし、変化を検出して通知する。

### 本通知の処理概要

FileChangesListener通知は、監視対象のディレクトリおよびそのサブディレクトリ内のファイル・ディレクトリの変更を検出し、登録されたリスナーに通知する仕組みである。

**業務上の目的・背景**：OpenSearchでは、設定ファイル、SSL証明書、認証情報ファイルなどが運用中に更新される可能性がある。これらのファイル変更を自動的に検出し、設定のリロードや証明書の更新を行うために、ファイル監視メカニズムが必要である。FileChangesListenerはこの監視結果を通知するインターフェースを提供する。

**通知の送信タイミング**：FileWatcherが定期的（ResourceWatcherServiceのスケジュールに基づく）にファイルシステムをポーリングし、変化を検出した時点で通知が発生する。初期化時にはonFileInit/onDirectoryInitが呼ばれる。その後のチェック時にファイルの作成・変更・削除、ディレクトリの作成・削除が検出されると対応するコールバックが呼ばれる。

**通知の受信者**：FileChangesListenerインターフェースを実装し、FileWatcher#addListener()で登録されたコンポーネント。

**通知内容の概要**：各コールバックにはPathオブジェクト（変更されたファイル/ディレクトリのパス）が渡される。7つのコールバック：onFileInit（初期化時既存ファイル）、onDirectoryInit（初期化時既存ディレクトリ）、onFileCreated（ファイル作成）、onFileDeleted（ファイル削除）、onFileChanged（ファイル変更）、onDirectoryCreated（ディレクトリ作成）、onDirectoryDeleted（ディレクトリ削除）。

**期待されるアクション**：受信者はファイル変更に応じて、設定のリロード、SSL証明書の更新、認証情報の再読み込みなどを実行する。

## 通知種別

プロセス内コールバック通知（Javaインターフェースによるリスナーパターン）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（ResourceWatcherServiceのスケジュールスレッド上で実行） |
| 優先度 | 中（ファイル変更検出は定期ポーリング） |
| リトライ | 無し（次回ポーリング時に再検出される可能性あり） |

### 送信先決定ロジック

FileWatcher（AbstractResourceWatcherを継承）のCopyOnWriteArrayList<FileChangesListener>に登録されたすべてのリスナーに対して順次通知する。addListener()で登録、remove()で解除。

## 通知テンプレート

### メール通知の場合

本通知はプロセス内コールバックであるため、メール通知は該当しない。

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | N/A |
| 送信元名称 | N/A |
| 件名 | N/A |
| 形式 | N/A |

### 本文テンプレート

```
N/A（Javaメソッドコールバック、Pathオブジェクトとして通知）
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | N/A | N/A | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| file | 変更されたファイル/ディレクトリのパス | java.nio.file.Path | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 初期化（ファイル） | FileWatcher初期化時の既存ファイル検出 | ファイルが存在すること | onFileInit(path) |
| 初期化（ディレクトリ） | FileWatcher初期化時の既存ディレクトリ検出 | ディレクトリが存在すること | onDirectoryInit(path) |
| ファイル作成 | 新規ファイルの検出 | 前回チェック時に存在せず今回存在するファイル | onFileCreated(path) |
| ファイル削除 | ファイルの消失検出 | 前回チェック時に存在し今回存在しないファイル | onFileDeleted(path) |
| ファイル変更 | ファイルのメタデータ変更検出 | lastModifiedTimeまたはsizeが変化したファイル | onFileChanged(path) |
| ディレクトリ作成 | 新規ディレクトリの検出 | 前回チェック時に存在せず今回存在するディレクトリ | onDirectoryCreated(path) |
| ディレクトリ削除 | ディレクトリの消失検出 | 前回チェック時に存在し今回存在しないディレクトリ | onDirectoryDeleted(path) |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ファイル変更なし | ポーリング時にファイルシステムの変化がなければ通知されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ResourceWatcherServiceによる定期ポーリング] --> B[FileWatcher#checkAndNotify]
    B --> C[FileObserver#checkAndNotify]
    C --> D{ファイル状態変化?}
    D -->|作成| E[onFileCreated / onDirectoryCreated]
    D -->|変更| F[onFileChanged]
    D -->|削除| G[onFileDeleted / onDirectoryDeleted]
    D -->|変化なし| H[スキップ]
    E --> I[登録済みリスナーを順次呼び出し]
    F --> I
    G --> I
    I --> J{例外発生?}
    J -->|Yes| K[警告ログ出力し次のリスナーへ]
    J -->|No| L[次のリスナーへ]
    K --> M[終了]
    L --> M
    H --> M
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | N/A | RDBは使用しない。ファイルシステムを直接ポーリング |

### テーブル別参照項目詳細

N/A

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| N/A | N/A | RDBは使用しない |

#### 送信ログテーブル

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| N/A | N/A | N/A | N/A |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| リスナー実行時例外 | コールバック内で例外がスローされた場合 | 警告ログ（"cannot notify file changes listener"）を出力して次のリスナーの処理を継続 |
| ファイルアクセスエラー | ファイルの属性読み取りに失敗 | IOExceptionが上位に伝搬 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（次回ポーリングサイクルで再検出される可能性あり） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（ポーリング間隔に依存） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ResourceWatcherServiceのスケジュールに従う）

## セキュリティ考慮事項

監視対象ファイルにはSSL証明書や認証情報が含まれる可能性がある。@opensearch.internalとしてマークされており、内部APIである。ファイルパス情報がリスナーに渡されるため、ログ出力時には機密パスの露出に注意が必要。

## 備考

- @opensearch.internalとしてマークされており、内部APIである
- 全メソッドがデフォルト実装（空）を持つため、必要なイベントのみオーバーライドすればよい
- ファイル変更の検出はlastModifiedTimeとsizeの比較で行われる（NIO2のWatchServiceは未使用）
- FileWatcherはAbstractResourceWatcherを継承し、CopyOnWriteArrayListでリスナーを管理
- clearState()メソッドで監視状態をリセット可能（全ファイルが新規として再検出される）
- ファイルがディレクトリに置換された場合はonFileDeleted→onDirectoryCreatedの順で通知される

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FileChangesListener.java | `server/src/main/java/org/opensearch/watcher/FileChangesListener.java` | 7つのコールバックメソッド定義（行45-75） |

**読解のコツ**: 初期化用コールバック（onFileInit/onDirectoryInit）と変更通知用コールバック（onFileCreated/Changed/Deleted/onDirectoryCreated/Deleted）を区別する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AbstractResourceWatcher.java | `server/src/main/java/org/opensearch/watcher/AbstractResourceWatcher.java` | リスナー管理（CopyOnWriteArrayList）とcheckAndNotify()のフレームワーク（行44-95） |
| 2-2 | FileWatcher.java | `server/src/main/java/org/opensearch/watcher/FileWatcher.java` | doInit()/doCheckAndNotify()の実装（行80-87）、FileObserver内部クラス（行91-） |

**主要処理フロー**:
1. **FileWatcher行80-81**: `doInit()` - rootFileObserver.init(true)で初期スキャン
2. **FileWatcher行85-87**: `doCheckAndNotify()` - rootFileObserver.checkAndNotify()で差分検出
3. **FileWatcher行103-170**: `FileObserver#checkAndNotify()` - ファイルの存在・サイズ・更新日時を比較して変更を検出
4. **FileWatcher行268-279**: `onFileCreated()` - listeners()を順次呼び出し、例外時は警告ログ
5. **FileWatcher行292-298**: `onFileChanged()` - 同様のリスナー呼び出しパターン

#### Step 3: ファイル変更検出ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FileWatcher.java | `server/src/main/java/org/opensearch/watcher/FileWatcher.java` | FileObserver#checkAndNotify()内の状態遷移ロジック（行128-168）、updateChildren()によるサブディレクトリの差分管理（行212-256） |

### プログラム呼び出し階層図

```
ResourceWatcherService (定期スケジュール)
    |
    +-- FileWatcher#checkAndNotify() [AbstractResourceWatcher行57]
            |
            +-- FileWatcher#doInit() [初回のみ, 行80]
            |       +-- FileObserver#init(true) [行81]
            |               +-- onFileCreated(initial=true) → listener.onFileInit() [行271-272]
            |               +-- onDirectoryCreated(initial=true) → listener.onDirectoryInit()
            |
            +-- FileWatcher#doCheckAndNotify() [行85]
                    +-- FileObserver#checkAndNotify() [行103]
                            |
                            +-- [ファイル作成] onFileCreated(false) → listener.onFileCreated() [行274]
                            +-- [ファイル変更] onFileChanged() → listener.onFileChanged() [行293]
                            +-- [ファイル削除] onFileDeleted() → listener.onFileDeleted() [行284]
                            +-- [ディレクトリ作成] onDirectoryCreated(false) → listener.onDirectoryCreated()
                            +-- [ディレクトリ削除] onDirectoryDeleted() → listener.onDirectoryDeleted()
```

### データフロー図

```
[入力]                           [処理]                               [出力]

ファイルシステム状態 ───▶ FileObserver#checkAndNotify()
                              |
                     前回状態との比較
                     (exists, length,
                      lastModified, isDirectory)
                              |
                     ┌────────┼──────────────┐
                     v        v              v
                  作成     変更           削除
                     |        |              |
                     v        v              v
              onFileCreated onFileChanged  onFileDeleted
              (path)        (path)         (path)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| FileChangesListener.java | `server/src/main/java/org/opensearch/watcher/FileChangesListener.java` | ソース | リスナーインターフェース定義 |
| FileWatcher.java | `server/src/main/java/org/opensearch/watcher/FileWatcher.java` | ソース | ファイル監視・変更検出・通知実行 |
| AbstractResourceWatcher.java | `server/src/main/java/org/opensearch/watcher/AbstractResourceWatcher.java` | ソース | リスナー管理フレームワーク |
| ResourceWatcher.java | `server/src/main/java/org/opensearch/watcher/ResourceWatcher.java` | ソース | リソース監視インターフェース |
