CSV形式のデータをグラフに表示するJenkins Plug-inの作成 (2)


# はじめに
前回はJenkins Pluginを作成し、CSVファイルのデータをテキストで表示するサンプルを作成しました。今回は、CSVファイルのデータをグラフ化するプラグインを作成したいと思います。前回の記事の続きになっていますので、前回の記事をお読みでない方は、前回の記事もご参照頂ければと思います。

http://qiita.com/yokobonbon/items/1f592de2884e928ca393

# JFreeChartを用いたグラフ化

グラフ化の方法はいろいろあると思いますが、plot pluginのソースコードを調査したところJFreeChartを使っていることが分かりました。このサンプルでも同様にJFreeChartを使用したいと思います。

http://www.jfree.org/jfreechart/

JFreeChartを用いたグラフ化は単純には以下のような流れになります

1. DefaultCategoryDatasetにデータを入力
2. ChartFactoryクラスを用いてdatasetからJFreeChartクラスを作成
3. JFreeChartクラスからPNGを作成

# CSVファイルからDatasetの作成
以下のようなCSVデータをパースします

```bash
echo "week, active, new" > kpi.csv
echo "w1,1000,100" >> kpi.csv                                    
echo "w2,1200,200" >>  kpi.csv                                    
echo "w3,1400,200" >> kpi.csv                                    
echo "w4,1500,100" >> kpi.csv
echo "w5,1600,100" >> kpi.csv
```

CSVからDatasetを作成するクラスです

```java
public class CsvDataset {
    public static CsvDataset parse(FilePath path) {
        try {
            if (!path.exists()) {
                return null;
            }
        } catch (IOException e2) {
            return null;
        } catch (InterruptedException e2) {
            return null;
        }

        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(path.read(), "UTF-8"));
        } catch (UnsupportedEncodingException e1) {
            return null;
        } catch (IOException e1) {
            return null;
        } catch (InterruptedException e1) {
            return null;
        }
        
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        String[] columns = null;
        try {
            String line = null;
            while ((line = reader.readLine()) != null) {
                if (columns == null) {
                    columns = line.split(",");
                } else {
                    addValues(dataset, columns, line);
                }
            }
        } catch (IOException e) {
            return null;
        }

        return new CsvDataset(dataset, columns[0]);
    }
    
    private static void addValues(DefaultCategoryDataset dataset, String[] columns, String line) {
        String[] values = line.split(",");
        if (columns.length != values.length) {
            return;
        }
        String rowKey = values[0];
        for (int i = 1; i < columns.length; i++) {
            Number value = retrieveValue(values[i]);
            if (value != null) {
                dataset.addValue(value, columns[i], rowKey);
            }
        }
    }
    
    private static Number retrieveValue(String valueStr) {
        Number value = null;
        try {
            value = Integer.valueOf(valueStr);
        } catch (NumberFormatException ie) {
            try {
                value = Double.valueOf(valueStr);
            } catch (NumberFormatException de) {
            }
        }
        return value;
    }
    
    private final DefaultCategoryDataset mDataset;
    
    private final String mCategoryLabel;
    
    private CsvDataset(DefaultCategoryDataset dataset, String categoryLabel) {
        mDataset = dataset;
        mCategoryLabel = categoryLabel;
    }
    
    public CategoryDataset getCategoryDataset() {
        return mDataset;
    }
    
    public String getCategoryLabel() {
        return mCategoryLabel;
    }
}
```

# CsvPublisherの拡張
グラフには、タイトルなどの追加情報が必要ですので、以下のようにタイトルと縦軸のラベルのパラメーターを追加します。

<img width="326" alt="スクリーンショット 2015-12-24 23.53.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/5c18c8d7-4cb5-4fe6-ae19-ca4b4ee8aab5.png">

config.jelly

```xml
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
  <!--
    This jelly script is used for per-project configuration.

    See global.jelly for a general discussion about jelly script.
  -->

  <f:entry title="File Name" field="fileName">
    <f:textbox />
  </f:entry>
  <f:entry title="Title" field="title">
    <f:textbox />
  </f:entry>
  <f:entry title="Value Label" field="valueLabel">
    <f:textbox />
  </f:entry>
</j:jelly>
```

CsvPublisher.java

```java
public class CsvPlotPublisher extends Recorder implements SimpleBuildStep {
    private final String mFileName;
    
    private final String mTitle;
    
    private final String mValueLabel;
    
    private FilePath mFilePath;
    
    @DataBoundConstructor
    public CsvPlotPublisher(String fileName, String title, String valueLabel) {
        mFileName = fileName;
        mTitle = title;
        mValueLabel = valueLabel;
    }
```

# グラフの表示

index.jellyからのグラフの表示ですが、JavaのコードからPNGのデータを受け取りそれを表示する形になります。ここではgetPlotでデータを取得していますが、ネーミングルールで、JavaではdoGetPlotというメソッドで呼び出す形になります。doGetPlotメソッド内でグラフを作成し、PNGを返してやればグラフの描画がされます。

index.jelly

```xml
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:c="chart">
  <l:layout title="${it.project.displayName}">
    <l:main-panel>
      <img src="getPlot" width="750" height="450" />
    </l:main-panel>
  </l:layout>    
</j:jelly>
```

CsvPlotAction.java

```java
    public void doGetPlot(StaplerRequest req, StaplerResponse rsp) {
        FilePath filePath = mPublisher.getFilePath();
        CsvDataset dataset = CsvDataset.parse(filePath);
        final JFreeChart chart = ChartFactory.createLineChart(mPublisher.getTitle(), 
                dataset.getCategoryLabel(), mPublisher.getValueLabel(), 
                dataset.getCategoryDataset(), PlotOrientation.VERTICAL, true, false, false);
        chart.setBackgroundPaint(ChartColor.WHITE);
        try {
            new Graph(-1, 750, 450) {
                protected JFreeChart createGraph() {
                    return chart;
                }
            }.doPng(req,rsp);
        } catch (IOException e) {
        }
    }
```

前回ではテキストで表示されていたCSV Plotメニューを選択するとグラフが出ました

<img width="800" alt="スクリーンショット 2015-12-24 23.54.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/85182/d849febe-8435-7986-008e-ce7016225de6.png">

# おわりに
plot plug-inを参考にして、ミニマムなCSVファイルからグラフ化するプラグインを作成しました。今後はこれを拡張して、様々な業務に役立てていきたいと思います。