倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

はじめての幻獣 Griffon 研 (8) : 外部ライブラリを使用する install-dependency

今回は外部ライブラリを使用する方法を見ていきます(一覧)。

FunctionPlotter プロジェクトのソース変更点


今回の変更で、以下の外部ライブラリを使用できるようにします:

group module version
org.apache.commons commons-math 2.1

FunctionPlotterController.groovy の変更

FunctionPlotterController.groovy 内の Dynamo クラスに関して

class Dynamo{
    ...

    Dynamo(String function){
        def expr = """
import static java.lang.Math.*
import static org.apache.commons.math.util.MathUtils.*       // commons-math 内のクラス
import static org.apache.commons.math.special.Beta.*        // commons-math 内のクラス
import static org.apache.commons.math.special.Gamma.*   // commons-math 内のクラス
import static org.apache.commons.math.special.Erf.*          // commons-math 内のクラス
$function"""
        this.functionScript = SHELL.parse(expr)
    }
}

のように、関数を表す文字列から Groovy スクリプトを生成する部分に commons-math のクラス(というか static メソッド)を自動 import されるようにしておきます。 これによって

  • MathUtils クラスの static メソッド
  • Beta クラスの static メソッド (ベータ関数関連)
  • Gamma クラスの static メソッド (ガンマ関数関連)
  • Erf クラスの static メソッド (誤差関数関連)

がメソッド名のみで使用できるようになります。

FunctionPlotterView.groovy の変更

上記の変更だけでもいいんですが、実行時にしか外部ライブラリを使用しないためサンプルとしては物足りないかなぁということで、(ちょっと無理矢理) View でも commons-math のクラスを使うようにしましょう:

...
import org.apache.commons.math.util.MathUtils as CMath    // commons-math 内のクラス

actions{ ... }

application(title: 'Function Plotter', ...){
    panel(border:BF.createEmptyBorder(6, 6, 6, 6)){
        ...
        hbox(constraints: BL.SOUTH){
            hstrut(width:10)
            labeledSpinner('from', 0d)
            10.times{ hglue() }
            labeledSpinner('to', CMath.TWO_PI)    // commons-math のクラスを使う
        }
    }
}

ソースコードの変更はたわいなし。

外部ライブラリを使用できるようにするための設定


Griffon で外部ライブラリを使用できるようにするためには、次の2つの方法があります:

  • lib フォルダに Jar ファイルを配置する (install-dependency)
  • BuildConfig.groovy ファイルに設定を記述する

この設定はどちらか一方で構いません。 lib フォルダに Jar ファイルがあれば BuildConfig.groovy に設定を記述する必要はありませんし、vice も versa です。

lib フォルダに Jar ファイルを配置する install-dependency

プロジェクト・ルートのフォルダ下にある lib フォルダに Jar ファイルを配置すると、特に他の設定をしなくてもコンパイルや実行の際にそのライブラリをクラスパスに含めてくれるようです。 ただ、全てのライブラリとそれに必要なライブラリを手動でダウンロードするのは面倒なので、griffon コマンドでそれらのライブラリをダウンロードしましょう。

使用するコマンドは「griffon install-dependency」です。 プロジェクト・ルートのフォルダ下にて、これに続けて「必要なライブラリの指定」と「ダウンロード先*1」を指定します:

griffon install-dependency org.apache.commons:commons-math:2.1 --dir=lib

ライブラリの指定方法は「《グループ名》:《ライブラリ名》:《バージョン》」です*2

Griffon のドキュメント*3を見るとこれで OK なハズなんですが、実際には何故か lib フォルダではなく true フォルダ下にライブラリがダウンロードされます・・・ん〜まぁ、単なるケアレス・バグでしょう。 修正されるまでは、面倒ですが手動で移動させるしかないですね。

BuildConfig.groovy ファイルに設定を記述する

次は BuildConfig.groovy ファイルに設定を記述する方法*4。 BuildConfig.groovy ファイルは

  • FunctionPlotter/griffon-app/conf/BuildConfig.groovy

にあります。 このファイルの griffon.project.dependency.resolution を設定している箇所に設定を追加します。

griffon.project.dependency.resolution = {
    ...
    repositories {
        griffonPlugins()
        griffonHome()
        griffonCentral()

        //mavenLocal()    // Maven のローカル・リポジトリ
        mavenCentral()    // Maven のリモート・リポジトリ
    }
    dependencies {
        // 'build', 'compile', 'runtime', 'test' 'provided' のいずれかのスコープを指定する
        compile 'org.apache.commons:commons-math:2.1'
        //runtime 'org.apache.commons:commons-math:2.1'
    }
}
  • Maven2 のリモート・リポジトリをライブラリ検索に使用したい場合は、repositories ノード下の mavenCentral() のコメントを外す*5
  • dependencies ノード下に、使用したいライブラリとそのスコープを指定する

指定できるスコープの意味は以下のようになっています:

スコープ 説明
build ビルドシステムに必要
compile コンパイルに必要
runtime コンパイルには不必要だが実行時に必要
test 実行時には不必要だがテスト時に必要
provided WAR の配備時には不必要だが開発時に必要

だいたい Maven2 のスコープと同じですね。 ただ、そういう仕様なのか単なるバグなのか不明なのですが、Griffon では compile スコープのライブラリは実行時にクラスパスに含められないようになっています*6 *7。 仕方ないので、compile, runtime 両方にライブラリの指定をすることにしましょう*8

    dependencies{
        def compile_runtime = 'org.apache.commons:commons-math:2.1'
        compile compile_runtime
        runtime compile_runtime
    }

実行結果


ソースコードの変更と、上記のうちいずれかの外部ライブラリを使用するための設定を行った後、FunctionPlotter を実行して

griffon run-app

関数の箇所に「erf(x)」(erf() は org.apache.commons.math.special.Erf クラスの static メソッド)を入力してグラフを描画すると、以下のように表示されます:


きちんと描画されてるかどうかは wikipedia:誤差関数と見比べて確認してください。

依存している Jar の一覧を作成する dependency-report


特に必要な事項ではありませんが、ライブラリの依存性を俯瞰したい場合は

griffon dependency-report

を実行すると依存性のレポートが生成されます。 レポートは HTML 形式で

  • ${FunctionPlotter}/target/dependency-report

フォルダに作成されます。 生成されたページを見る限り、Apache Ivy の機能をそのまま流用してるようですね。

追記


Griffon 0.9.2-beta-3 では、compile スコープで指定したライブラリは runtime にも含まれるようになってました。 ちなみに Gradle でも、脚注に書いた「extendsFrom compile」みたいなのを書かなくても compile スコープのライブラリは runtimeに含まれるようです(Gradle 0.9.2)。
Apache Maven 2.0入門 Java・オープンソース・ビルドツール

Apache Maven 2.0入門 Java・オープンソース・ビルドツール

*1:ダウンロード先を指定しない場合は(指定してもだけど) ${user.home}/.ivy2/cache にキャッシュが保存されます。 Maven2ローカル・リポジトリの役割。

*2:Maven2 の用語だと「《groupId》:《artifactId》:《version》」です。

*3:Griffon Guide - Reference Documentation」 CommandLine → install-dependency 参照。

*4:詳しくは「Griffon Guide - Reference Documentation」 3.4 Dependency Resolution の項参照。

*5:上記の install-dependency コマンドの場合は自動でこのリポジトリを検索してくれるようです。

*6:Griffon のドキュメントを見ると compile スコープは「Dependencies for the compile step」となっていて、実行時に関しては何も書かれていないのでそういう仕様なのかも知れませんが、後でやる「griffon dependency-report」で生成されるレポートには runtime スコープの箇所に compile スコープのライブラリも掲載されています。 うーむ、謎。

*7:Gradle ではどうなっているのか確かめていませんが、少なくとも「configurations.runtime { extendsFrom compile }」とすれば compile スコープのライブラリをそのまま runtime にも引き継がせることができそうです。 Griffon で似たようなことをするにはどこに設定を書いたものか・・・

*8:compile スコープのみを指定して、全てのライブラリを1つの jar にまとめる「griffon prod package jar」を実行しても大丈夫そうです。 dist/jar 下に実行可能な Jar ファイルが作成されます。