# 帳票設計書 2-汎用グラフ

## 概要

本ドキュメントは、Jenkins CI/CDサーバーにおける汎用グラフ生成機能の帳票設計書である。JFreeChartライブラリを使用した汎用的なグラフ生成基盤クラス `hudson.util.Graph` について記述する。

### 本帳票の処理概要

この帳票は、Jenkinsの各種統計情報やメトリクスを視覚化するための汎用グラフ生成基盤を提供する。抽象クラスとして設計されており、具象実装クラスがグラフの内容を定義する。PNG形式の画像とクリッカブルマップ（HTML imagemap）を生成する機能を持つ。

**業務上の目的・背景**：Jenkinsでは、テスト結果のトレンド、コードカバレッジの推移、ビルド時間の統計など、様々なメトリクスをグラフで可視化するニーズがある。これらを個別に実装するのではなく、共通の基盤クラスを提供することで、プラグイン開発者が容易にグラフ機能を実装できるようにしている。

**帳票の利用シーン**：プラグインやJenkinsコア機能が時系列データや統計データを視覚化する際に利用される。テスト結果プラグイン、コードカバレッジプラグイン、ビルド統計など多様な場面で活用される。

**主要な出力内容**：
1. PNG形式のグラフ画像（/png エンドポイント）
2. クリッカブルマップ（/map エンドポイント）- グラフ上の各要素をクリック可能にするHTMLマップ

**帳票の出力タイミング**：ユーザーがグラフを表示するページにアクセスした際に、JavaScriptまたはimg要素から /png エンドポイントが呼び出される。

**帳票の利用者**：Jenkins管理者、開発者、QAエンジニア（グラフを閲覧する全ユーザー）、プラグイン開発者（Graphクラスを継承して実装）

## 帳票種別

統計グラフ（汎用基盤クラス）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | （各種統計画面） | `{オブジェクトURL}/png` | img要素のsrcとして参照 |
| - | （各種統計画面） | `{オブジェクトURL}/map` | クリッカブルマップ取得 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | PNG（画像）/ text/plain（マップ） |
| 用紙サイズ | 可変（デフォルト値はコンストラクタで指定） |
| 向き | - |
| ファイル名 | 動的生成（ストリームとして出力） |
| 出力方法 | HTTP レスポンスとして直接配信 |
| 文字コード | UTF-8（マップのみ） |

### PNG固有設定

| 項目 | 内容 |
|-----|------|
| 最大面積 | 10,000,000 ピクセル（4K x 2.5K相当） |
| 背景色 | パラメータで指定可能（デフォルト: 白） |
| プロット背景色 | パラメータで指定可能（デフォルト: 白） |
| スケール | 最大3倍 |

### パラメータ一覧

| パラメータ名 | 説明 | デフォルト値 |
|------------|------|-------------|
| width | グラフの幅（ピクセル） | コンストラクタ指定値 |
| height | グラフの高さ（ピクセル） | コンストラクタ指定値 |
| scale | 拡大率（1-3） | 1 |
| graphBg | グラフ背景色（16進数） | FFFFFF（白） |
| plotBg | プロット領域背景色（16進数） | FFFFFF（白） |

## 帳票レイアウト

### レイアウト概要

具象クラスの `createGraph()` メソッドの実装により決定される。JFreeChartの全てのチャートタイプが利用可能。

```
┌─────────────────────────────────────┐
│         JFreeChart グラフ領域        │
│                                     │
│    （実装クラスにより内容が決定）      │
│                                     │
└─────────────────────────────────────┘
```

### ヘッダー部

実装クラスに依存

### 明細部

実装クラスに依存

### フッター部

実装クラスに依存

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| width | グラフ幅（最大2560px） | No |
| height | グラフ高さ（最大1440px） | No |
| scale | 拡大率（最大3） | No |
| graphBg | 背景色（16進数） | No |
| plotBg | プロット背景色（16進数） | No |

### ソート順

実装クラスに依存

### 改ページ条件

単一画像のため改ページなし

## データベース参照仕様

### 参照テーブル一覧

本クラスは抽象クラスであり、データ取得は具象クラスの責務となる。

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| JFreeChart | グラフオブジェクト | createGraph()で生成 |
| ChartRenderingInfo | クリッカブルマップ情報 | render時に生成 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 安全なサイズ | width * height <= MAX_AREA | - | 超過時はデフォルト値使用 |
| 出力サイズ | (width * scale, height * scale) | 整数 | BufferedImage生成時 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[HTTPリクエスト /png] --> B[キャッシュチェック]
    B -->|変更なし| C[304 Not Modified]
    B -->|変更あり| D[パラメータ解析]
    D --> E[safeDimension計算]
    E --> F[createGraph呼び出し]
    F --> G[BufferedImage生成]
    G --> H[PNG書き出し]
    H --> I[レスポンス返却]
```

```mermaid
flowchart TD
    A[HTTPリクエスト /map] --> B[キャッシュチェック]
    B -->|変更なし| C[304 Not Modified]
    B -->|変更あり| D[render with ChartRenderingInfo]
    D --> E[getImageMap生成]
    E --> F[テキストレスポンス返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| HeadlessException | GUIサポートなしの環境 | /images/headless.png へリダイレクト | java.awt.headlessモードの設定確認 |
| フォントなしError | システムフォントが見つからない | /images/headless.png へリダイレクト | システムにフォントをインストール |
| NumberFormatException | 不正な色指定 | デフォルト色（白）を使用 | - |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 実装クラスに依存 |
| 目標出力時間 | 実装クラスに依存 |
| 同時出力数上限 | 特に制限なし（メモリ依存） |
| キャッシュ | timestampによるHTTPキャッシュ対応 |

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

- パラメータ（width, height, scale）に上限値を設定し、DoS攻撃を防止
- MAX_AREA（10,000,000ピクセル）を超えるサイズはデフォルト値にフォールバック
- 色指定パラメータはNumberFormatExceptionをキャッチしてデフォルト値を使用

## 備考

- このクラスは抽象クラスであり、`createGraph()` メソッドをオーバーライドして使用する
- timestampを-1に設定するとHTTPキャッシュを無効化できる
- JFreeChartの全機能が利用可能（折れ線、棒、円、散布図など）

---

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

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

### 推奨読解順序

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

まず、Graph クラスの基本構造とフィールドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Graph.java | `core/src/main/java/hudson/util/Graph.java` | クラス定義とフィールド（行69-78） |

**読解のコツ**: `timestamp`、`defaultWidth`、`defaultHeight` の3つのフィールドがコンストラクタで初期化される点に注目。`graph` フィールドはvolatileで遅延初期化される。

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

HTTPリクエストを受け付けるエンドポイントを特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Graph.java | `core/src/main/java/hudson/util/Graph.java` | `doPng()` メソッド（行159-174） |
| 2-2 | Graph.java | `core/src/main/java/hudson/util/Graph.java` | `doMap()` メソッド（行232-247） |

**主要処理フロー**:
1. **行159-165**: `doPng(StaplerRequest2, StaplerResponse2)` でリクエスト受付
2. **行176-225**: `doPngImpl()` で実際の画像生成処理
3. **行177**: `req.checkIfModified()` でキャッシュチェック
4. **行180**: `render()` メソッドでBufferedImage生成
5. **行183**: ImageIO.write()でPNG出力

#### Step 3: グラフレンダリングを理解する

画像生成の中核処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Graph.java | `core/src/main/java/hudson/util/Graph.java` | `render()` メソッド（行100-130） |

**主要処理フロー**:
- **行101-114**: クエリパラメータの解析（width, height, scale, graphBg, plotBg）
- **行116-118**: 背景色の設定
- **行119**: `createGraph()` の遅延呼び出し
- **行124-126**: サイズの上限チェック
- **行127-129**: `safeDimension()` で安全なサイズを計算
- **行128-129**: BufferedImage生成

#### Step 4: サイズ制限ロジックを理解する

セキュリティとパフォーマンスのためのサイズ制限。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Graph.java | `core/src/main/java/hudson/util/Graph.java` | `safeDimension()` メソッド（行134-140） |

**主要処理フロー**:
- **行71**: MAX_AREA定数（10,000,000ピクセル）
- **行135-138**: width * height > MAX_AREA の場合はデフォルト値にフォールバック

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

```
doPng(req, rsp)
    │
    ├─ req.checkIfModified(timestamp, rsp)
    │      └─ [304 Not Modified を返却する可能性]
    │
    └─ render(req, info)
           │
           ├─ パラメータ解析（width, height, scale, graphBg, plotBg）
           │
           ├─ stringToColor(param)
           │
           ├─ createGraph() [抽象メソッド - 具象クラスで実装]
           │
           ├─ safeDimension(width, height, defaultWidth, defaultHeight)
           │
           └─ graph.createBufferedImage(...)
                  │
                  └─ ImageIO.write(image, "PNG", os)
```

```
doMap(req, rsp)
    │
    ├─ req.checkIfModified(timestamp, rsp)
    │
    └─ render(req, info)
           │
           └─ ChartUtilities.getImageMap("map", info)
```

### データフロー図

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

HTTPリクエスト ──────▶ doPng()
   /png                      │
   ?width=800                │
   &height=600               ▼
   &scale=2          render(req, info)
                             │
                             ▼
                    createGraph() [具象クラス]
                             │
                             ▼
                    graph.createBufferedImage()
                             │
                             ▼
                    ImageIO.write() ─────────────▶ PNG画像
                                                  (HTTPレスポンス)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Graph.java | `core/src/main/java/hudson/util/Graph.java` | ソース | 汎用グラフ基盤クラス |
| ChartUtil.java | `core/src/main/java/hudson/util/ChartUtil.java` | ソース | グラフユーティリティ |
| GraphTest.java | `core/src/test/java/hudson/util/GraphTest.java` | テスト | Graphクラスのテスト |
| StaplerRequest2.java | (Stapler ライブラリ) | 外部 | HTTPリクエスト抽象化 |
| StaplerResponse2.java | (Stapler ライブラリ) | 外部 | HTTPレスポンス抽象化 |
| JFreeChart.java | (JFreeChart ライブラリ) | 外部 | グラフライブラリ |
| ChartRenderingInfo.java | (JFreeChart ライブラリ) | 外部 | クリッカブルマップ情報 |
