マッパー関数開発者ガイド

  1. マッパー関数開発について
    1. JDK・クラスパス
  2. Valueクラスについて
  3. Functionサブクラスの作成
    1. 必ず実装するメソッド
      1. マッパー関数名の命名規則について
    2. 必要に応じてオーバーライドするメソッド
  4. プロパティ
    1. プロパティの登録
    2. プロパティの取得
  5. MultiOutputFunctionの作成
    1. サブ出力の設定
  6. サンプル

1 マッパー関数開発について

フローサービスでは独自のマッパー関数をJavaで開発し追加することが可能になっています。
マッパー関数開発を行う場合、以下の作業が必要になります。

jarファイルの作成に関しては実際にはJavaInterpreter関数付属のSDKウィザードでほぼ自動化されています。
ここではFunctionクラスのソースコードの書き方に絞って説明します。
定義ファイルの作成に関しては定義ファイルリファレンスを、 jarファイルの作成とそのインストールに関してはツールガイドを参照してください。

1.1 JDK・クラスパス

マッパー関数の開発はJDK5.0以降の環境で行ってください。
また、「DESIGNER_HOME/lib」にある以下のjarファイルにクラスパスを通す必要があります。

実際にはウィザードで生成されるANT用のbuild.xmlでは「DESIGNER_HOME/lib/**.*.jar」にクラスパスが通っています。
作成するプログラムの内容によってはさらに別のjarファイルがコンパイル/実行に必要になる場合があるので、通常はbuild.xmlの設定を変更する必要はありません。

2 Valueクラスについて

Valueとはフローサービスの基本データ型をラップするバリアント型の変数クラスのことです。
このクラスを使用することで変数の値をStringとして取り出したり、intとして取り出したりということが簡単にできます。

マッパー関数では入力されたフィールドの値がValueの配列として取得されます。

3 Functionサブクラスの作成

3.1 必ず実装するメソッド

Functionクラスでは次の3つのメソッドがabstractで宣言されているので必ず実装する必要があります。
public String getFunctionName();
マッパー関数の登録名を返すメソッド。
ここで返されるマッパー関数名はサーバー上に登録されるすべてのマッパー関数内でユニークでなければなりません。
protected void internalInit();
ここでプロパティの登録を行います。
作成するマッパー関数がプロパティを持たない場合は空で構いません。
public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException;
マッパー関数の処理本体を記述します。
引数のinには入力された値の配列が設定されています。
処理結果は引数のoutに設定します。

メソッドがMapperExceptionをthrowした場合はMapperコンポーネントのExceptionとしてフローのExceptionフレームワークに処理されます。
以下にexecuteメソッドの実装例を何パターンか示します。

//入力2つの文字列を結合する
public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
    out.setValue(in[0].strValue() + in[1].strValue());
}

//入力2つを整数として足す
public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
    out.setValue(in[0].longValue() + in[1].longValue());
}

//入力2つの文字列を結合する
public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
    out.setValue(in[0].strValue() + in[1].strValue());
}

ex7. Exceptionの使用 

//入力文字列がLengthプロパティ値よりも長い場合はExceptionにする
public void execute(ExecuteContext context, Value[] in, Value out) throws MapperException {
    int len = (int)getPropertyInteger("Length");
    if (in[0].strValue().length() >= len)
        throw new MapperException("入力が長すぎます。");
    else
        out.setValue(in[0]);
}

3.1.1 マッパー関数名の命名規則について

マッパー関数名(getFunctionNameメソッドの返り値)には「<会社名>.」というプレフィクスをつけてください。
Infoteria以外の会社が「.」を含まない名前を関数名に使用することは禁止事項とします。

3.2 必要に応じてオーバーライドするメソッド

以下のメソッドは必要に応じてオーバーライドします。
getMinInputCount()/getMaxInputCount()以外のメソッドはほとんどの場合実装する必要はありませんが、 処理を行うタイミングをコントロールすることでパフォーマンスが向上する可能性があります。

public void init(MapperComponent mapper, ExecuteContext context) throws MapperException;
マッパー関数が初期化される時に一度だけ呼び出されます。 (Mapperコンポーネントのinitメソッド内で呼び出されます。)
オーバーライドする場合、その先頭で、super.init(mapper, context);を呼び出す必要があります。
public void term(MapperComponent mapper, ExecuteContext context);
マッパー関数の終末処理時に一度だけ呼び出されます。 (Mapperコンポーネントのtermメソッド内で呼び出されます。)
オーバーライドする場合、その最後で、super.term(mapper, context);を呼び出す必要があります。
protected void postCompile() throws MapperException;
マッパー関数のコンパイル時にプロパティが設定された後で呼び出されます。
プロパティ間の整合性のチェックや、コンパイル時に一度だけ実行すればよい処理がある場合はここに記述します。
このメソッド内でMapperExceptionをthrowした場合はコンパイルエラーとなります。
public int getMinInputCount();
作成するマッパー関数の実行に必要な接続数を返します。
入力接続数がこのメソッドの返り値未満の場合はコンパイルエラーとなります。
オーバーライドしない場合は 1を返します。
public int getMaxInputCount();
作成するマッパー関数に接続できる入力数の最大値を返します。
入力接続を無制限に受け入れる場合は -1を返すようにします。
それ以外の場合に入力接続数がこのメソッドの返り値を超えている場合はコンパイルエラーとなります。
オーバーライドしない場合は 1を返します。

マッパー関数もコンポーネントと同じく、フローのリクエスト時にcloneメソッドによって複製が作られますが、その実装は コンポーネントとは異なり、Object#cloneメソッドにより実装されています。
つまりpostCompileメソッド内でインスタンス変数に設定したObjectは複製時にポインタがコピーされます。

4 プロパティ

4.1 プロパティの登録

プロパティの登録はinternalInitメソッド内でregistPropertyメソッドを呼び出すことによって行います。


    private static final String PROPERTY_DATA = "Data";
    private static final String PROPERTY_ENABLE_METACHARACTER = "EnableMetaCharacter";

    protected void internalInit() {
        registProperty(PROPERTY_DATA, Value.TYPE_STRING, false);
        registProperty(PROPERTY_ENABLE_METACHARACTER, Value.TYPE_BOOLEAN, false);
    }

4.2 プロパティの取得

プロパティ値を取得するにはgetPropertyメソッドを使用します。
あるいはgetPropertyXXXXメソッドを使用することでValueオブジェクトとしてではなく、プリミティブ型として取得することもできます。

マッパー関数のプロパティには「入力がn本以上ある場合にはプロパティの設定値の代わりにm番目の入力値を使用する」という仕様のものがありますが、このためのメソッドも標準で提供されています。
この場合はgetPropertyまたはgetPropertyXXXXメソッドの第2引数に入力値の配列(executeメソッドの引数 in)を、第3引数に何番目の値がプロパティを置換するのかを指定します。


    //Dataプロパティの内容をValueとして取得
    Value v = getProperty("Data");
    
    //入力値の配列(executeメソッドの引数 in)が2つ以上あればその2番目を、
    //それがない場合はCountプロパティの値をintとして取得
    int count = (int)getPropertyInteger("Count", in, 1);

5 MultiOutputFunctionの作成

MultiOutputFunctionとは出力が複数あるマッパー関数のことです。
出力がひとつだけの通常のマッパー関数とは次の点が異なります。

5.1 サブ出力の設定

setSubValueCountメソッドはマッパー関数の出力数を設定するメソッドです。
通常はコンストラクタの中で実行して出力数を設定します。

引数となる数字には2番目以降のサブ出力の数を設定することに注意してください。
つまり全部で4つの出力があるマッパー関数を作成する場合、設定する値は3です。

同様にgetSubValueメソッドの引数も2番目の出力以降のインデックスとなっています。
つまりgetSubValue(0)は全体で2番目の出力値です。



//出力が4つあるマッパー関数
public class FourOutputFunction extends MultiOutputFunction {

    public FourOutputFunction() {
        setSubValueCount(3);
    }
    
    public void execute(ExecuteContext context, Value[] in, Value out) {
        out.setValue("a");
        getSubValue(0).setValue("b");
        getSubValue(1).setValue("c");
        getSubValue(2).setValue("d");
    }
}

JavaInterpreterのようにプロパティ値によって動的に出力数の変わるマッパー関数ではコンストラクタでbDynamicをtrueにした上で postCompileメソッドで出力数を設定します。



//JavaInterpreter(抜粋)
public class JavaInterpreter extends MultiOutputFunction
{

	private static final String PROPERTY_COUNT = "Count";

	public JavaInterpreter() {
		super(true);
	}
	
	protected void postCompile(AbstractCompiler compiler) {
		int count = (int)getPropertyInteger(PROPERTY_COUNT);
		if (count > 1) 
			setSubValueCount(count);
	}
    
    ...
}

MultiOutputFunctionではメインの出力とサブ出力の複数の出力コネクタが画面に表示されるわけですが、そのうちのどれかひとつのコネクタに対してリンクがあればその関数は実行されます。
例えばDateSplit関数で曜日(4番目の出力コネクタ)にのみリンク線を繋いで、残りのコネクタは空であっても何の問題もありません。

このことをさらに進めて考えると「空のコネクタは画面に表示されていなくても良い」ということになります。

DateSplit関数もプロパティ値によって動的に出力数が変わる関数ですが、こちらはJavaInterpterとは違いコンストラクタ内で静的に出力数を設定しています。(サンプル参照)
つまり実際にはDateSplit関数の出力は常に8つあるわけですが、定義ファイルの設定で画面に4つしか見えてないことがあるということです。
もちろんJavaInterpreterのように動的にコネクタ数の増減する関数として作成することもできますが、そこは好みの問題でありどちらを選択した場合でもほとんど差はありません。

6 サンプル

サンプルとして標準で提供されているマッパー関数のいくつかのソースを公開します。