intra-mart Accel Platform IM-LogicDesigner拡張プログラミングガイド 第3版 2016-12-01

4. フロー要素

本章では、フロー実行時に呼び出されるフロー要素の作成方法を解説します。
フロー要素を追加するには、以下のクラスを作成する必要があります。
  • カテゴリ
  • フロー要素
  • メタデータ

カテゴリは一度作成を行ったら、再利用することが可能です。

4.1. カテゴリの作成

はじめに、フロー要素が所属するカテゴリの作成を行います。
カテゴリは、ロジックフローのデザイナ画面左部に表示されるパレットで利用されます。
カテゴリは全てJavaクラスで作成する必要があります。
カテゴリは jp.co.intra_mart.foundation.logic.element.category.ElementCategory インタフェースを実装したカテゴリクラスを作成してください。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.element.category.ElementCategory;

public class MyCategory implements ElementCategory {

    @Override
    public String getCategoryId() {
        return "my_category";
    }

    @Override
    public String getDisplayName() {
        return "サンプルカテゴリ";
    }

    @Override
    public int getSortNumber() {
        return 100;
    }
}
  • getCategoryId には、カテゴリのIDとなる文字列を返却するよう実装します。
    getCategoryIdには、 im_ で始まる文字列は利用できません。
  • getDisplayName は、画面上に表示されるカテゴリ名を返却するよう実装します。
    多言語化を行う場合には、MessageManager API等を利用して利用者のロケールに沿ったカテゴリ名を返却するよう実装を行う必要があります。
  • getSortNumber は、カテゴリを表示する際に利用するソート順となります。getSortNumberの値が小さい数ほど先頭に表示されるようになります。
    標準機能のソート番号は、1以降の連番を利用しています。

4.2. フロー要素とメタデータの作成

4.2.1. フロー要素の引数、戻り値の作成

フロー要素は、ロジックフロー実行時に指定のメソッドが呼び出されます。
指定のメソッドには任意の引数、戻り値を用意することが可能です。
引数、戻り値に利用可能なデータ型は以下の通りです。
  • プリミティブ型
  • java.lang.String
  • java.lang.Boolean
  • java.lang.Byte
  • java.lang.Character
  • java.lang.Short
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Float
  • java.lang.Double
  • java.math.BigDecimal
  • java.math.BigInteger
  • java.util.Calendar
  • java.util.Date
  • java.util.Locale
  • java.util.TimeZone
  • jp.co.intra_mart.foundation.i18n.datetime.DateTime
  • jp.co.intra_mart.foundation.i18n.datetime.Duration
  • java.sql.Date
  • java.sql.Timestamp
  • jp.co.intra_mart.foundation.logic.data.basic.ByteArrayBinary
  • jp.co.intra_mart.foundation.logic.data.basic.InputStreamBinary
  • jp.co.intra_mart.foundation.service.client.file.PublicStorage
  • jp.co.intra_mart.foundation.service.client.file.SessionScopeStorage
  • java.util.Mapを実装するクラス java.util.HashMap等
  • java.lang.Object
上記のデータ型を内包する java.util.Collection インタフェース、または、java.util.List インタフェースの実装クラス(ArrayList, LinkedList等)を利用することが可能です。
Collection、Listを利用した場合には、@TypeHint アノテーションを付与し、Collection、Listが内包する型を指定する必要があります。
@TypeHint アノテーションは、読み取り用メソッドに付与してください。
ここでは、引数、戻り値となるクラスを作成します。作成するクラスが持つプロパティを利用するには、対象のプロパティに対するgetter、および、setterを持つ必要があります。
実装するgetter、および、setterはJavaBeansの規約に沿って実装を行ってください。
package org.example.logicdesigner.element;

import java.util.Collection;

import jp.co.intra_mart.foundation.logic.annotation.TypeHint;

public class MyParameter {

    private String stringParameter;
    private boolean booleanParameter;
    private String[] stringArrayParameter;
    private Collection<Integer> integerListParameter;

    public String getStringParameter() {
        return stringParameter;
    }

    public void setStringParameter(String stringParameter) {
        this.stringParameter = stringParameter;
    }

    public boolean isBooleanParameter() {
        return booleanParameter;
    }

    public void setBooleanParameter(boolean booleanParameter) {
        this.booleanParameter = booleanParameter;
    }

    public String[] getStringArrayParameter() {
        return stringArrayParameter;
    }

    public void setStringArrayParameter(String[] stringArrayParameter) {
        this.stringArrayParameter = stringArrayParameter;
    }

    @TypeHint(Integer.class)
    public Collection<Integer> getIntegerListParameter() {
        return integerListParameter;
    }

    public void setIntegerListParameter(Collection<Integer> integerListParameter) {
        this.integerListParameter = integerListParameter;
    }
}
package org.example.logicdesigner.element;

public class MyResult {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

4.2.2. フロー要素、メタデータクラスの作成

次に、メインのクラスとなるフロー要素クラスを実装していきます。
フロー要素を作成する前に、フロー要素に対応したメタデータクラスを作成します。
メタデータクラスは、jp.co.intra_mart.foundation.logic.element.metadata.FlowElementMetadata クラスを継承して作成してください。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.element.metadata.FlowElementMetadata;

public class MyTaskMetadata extends FlowElementMetadata {

    public MyTaskMetadata() {
        super(null);
    }

    @Override
    public String getElementName() {
        return "サンプルタスク";
    }
}
  • getElementName メソッドは、パレット上に表示される名前となります。
    多言語化を行う場合には、MessageManager API等を利用して利用者のロケールに沿った要素名を返却するよう実装を行う必要があります。
  • コンストラクタ内で呼び出しを行っている super(null)部分は暫定的に記述しています。この部分はフロー要素クラスを作成後に変更を行います。
メタデータクラスを作成したら、フロー要素クラスを作成します。
フロー要素は、jp.co.intra_mart.foundation.logic.element.Task クラスを継承して作成してください。
Taskクラスには、3つの型パラメータを指定します。メタデータクラス、Taskに受け渡される引数の型、Taskが返却する戻り値の型を指定してください。
ここでは前項で作成したパラメータ用の型と返却用の型を指定します。
また、フロー要素には、jp.co.intra_mart.foundation.logic.annotation.LogicFlowElement アノテーションを付与する必要があります。LogicFlowElementアノテーションが付与されたクラスは起動時に自動的に読み込まれます。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.element.ElementContext;
import jp.co.intra_mart.foundation.logic.element.Task;
import jp.co.intra_mart.foundation.logic.exception.FlowExecutionException;

@LogicFlowElement(id="my_task", category=MyCategory.class, index=100)
public class MyTask extends Task<MyTaskMetadata, MyParameter, MyResult> {

    public MyTask(ElementContext context) {
        super(context);
    }

    @Override
    public MyResult execute(MyParameter parameter) throws FlowExecutionException {

        System.out.println(parameter.getStringParameter());

        MyResult result = new MyResult();
        result.setMessage("hello world.");
        return result;
    }
}
  • executeメソッドがフロー要素実行時に呼び出されるメソッドとなります。任意の処理を記述してください。

  • LogicFlowElementアノテーションには、そのフロー要素のID(id)、所属するカテゴリ(category)、パレットに表示する際に利用されるソート番号(index)を指定してください。

  • im_ で始まるIDを指定することは出来ません。前項で作成したMyCategoryクラスをカテゴリとして指定しています。

  • コンストラクタでは、ElementContext を引数に受け取ります。 ElementContext はフロー実行時の情報が格納されています。

  • 後述する FlowElementCloserElementContext に登録することにより、フロー実行後の後処理を行うプログラムを登録することが可能です。

  • フロー要素はロジックフロー実行時に都度インスタンスが生成されます。
    但し、繰り返し等で同一のフロー要素が呼び出される場合にはそのインスタンスは再利用されます。

次に、メタデータクラスを修正します。
メタデータクラスのコンストラクタ内で、親クラスのコンストラクタを呼び出している部分に、作成したフロー要素クラスを受け渡します。
メタデータクラスは、フロー要素のメタ情報を扱います。フロー要素の入力値、出力値が持つデータ型や、後述するプロパティに関する情報を提供する役割です。
親コンストラクタの引数にフロー要素クラスを受け渡すことにより、自動的にフロー要素の入力値、出力値が持つデータ型を解析し、メタ情報として内包します。
独自に入力値、出力値等のメタ情報を扱いたい場合には、 FlowElementMetadata の持つ各メソッドをオーバーライドしてください。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.element.metadata.FlowElementMetadata;

public class MyTaskMetadata extends FlowElementMetadata {

    public MyTaskMetadata() {
        super(MyTask.class);
    }

    @Override
    public String getElementName() {
        return "サンプルタスク";
    }
}
引数、戻り値、メタデータ、フロー要素の作成を行いました。
作成したクラスを intra-mart Accel Platform 上に配置することにより、作成したフロー要素が認識され利用できるようになります。

4.2.3. フロー要素にプロパティを追加する

フロー要素の引数、戻り値はロジックフローのマッピングにて利用されますが、引数、戻り値以外に、事前に決められた値を設定しておくためのプロパティ機構が存在します。
プロパティに利用可能なデータ型は以下の通りです。
  • プリミティブ型
  • java.lang.String
  • java.lang.Boolean
  • java.lang.Character
  • java.lang.Short
  • java.lang.Integer
  • java.lang.Long
  • java.lang.Float
  • java.lang.Double
  • java.math.BigDecimal
  • java.math.BigInteger
  • java.util.Date
  • java.sql.Date
  • java.sql.Timestamp
  • java.lang.Enum
プロパティを追加するには、フロー要素クラスにプロパティとして利用するフィールド、および、getter、 setterを追加します。
今回は、前項で作成した MyTaskcustomProperty という名のプロパティを追加します。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.element.ElementContext;
import jp.co.intra_mart.foundation.logic.element.Task;
import jp.co.intra_mart.foundation.logic.exception.FlowExecutionException;

@LogicFlowElement(id="my_task", category=MyCategory.class, index=100)
public class MyTask extends Task<MyTaskMetadata, MyParameter, MyResult> {

    private String customProperty;

    public MyTask(ElementContext context) {
        super(context);
    }

    public String getCustomProperty() {
        return customProperty;
    }

    public void setCustomProperty(String customProperty) {
        this.customProperty = customProperty;
    }

    @Override
    public MyResult execute(MyParameter parameter) throws FlowExecutionException {

        System.out.println(parameter.getStringParameter());

        MyResult result = new MyResult();
        result.setMessage("hello world.");
        return result;
    }
}
プロパティを追加したら、そのままデザイナの設定画面から値の設定を行うことが可能となります。
デザイナの設定画面では、 customProperty として項目名が表示されますが、メタデータクラスを変更することにより任意の表示名に変更することが可能です。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.element.metadata.FlowElementMetadata;
import jp.co.intra_mart.foundation.logic.element.metadata.ElementProperty;

public class MyTaskMetadata extends FlowElementMetadata {

    public MyTaskMetadata() {
        super(MyTask.class);
    }

    @Override
    public String getElementName() {
        return "サンプルタスク";
    }

    @Override
    protected ElementProperty decorateElementProperty(ElementProperty elementProperty) {
        if("customProperty".equals(elementProperty.getPropertyName())) {
            elementProperty.setDefaultValue("hello world.");
            elementProperty.setLabelKey("MYTASK.CUSTOMPROPERTY.LABEL.KEY");
        }
        return elementProperty;
    }
}
  • decorateElementProperty メソッドをオーバーライドし、プロパティ項目のカスタマイズが可能です。
  • setDefaultValue により、デフォルト値の指定を行っています。
  • setLabelKey にはプロパティの表示名にあたる多言語化リソースのキーを指定します。
  • setType メソッドを利用することにより画面上変更することが可能です。プロパティにboolean型を指定し、flag タイプを指定することによりチェックボックスとして扱えます。

4.2.4. フロー要素に後処理を追加する

ロジックフロー実行後に、任意の処理を呼び出すことが可能です。
これは、フロー要素内で使用したリソースの開放等を行う際に利用します。
後処理は、 jp.co.intra_mart.foundation.logic.element.FlowElementCloser インタフェースを実装する必要があります。
本項では、作成した MyTask クラスに直接 FlowElementCloser インタフェースを実装しています。
フロー要素のコンストラクタに受け渡される ElementContext に対し、 addFlowElementCloser メソッドで FlowElementCloser を登録します。
package org.example.logicdesigner.element;

import jp.co.intra_mart.foundation.logic.annotation.LogicFlowElement;
import jp.co.intra_mart.foundation.logic.element.ElementContext;
import jp.co.intra_mart.foundation.logic.element.FlowElementCloser;
import jp.co.intra_mart.foundation.logic.element.Task;
import jp.co.intra_mart.foundation.logic.exception.FlowExecutionException;

@LogicFlowElement(id = "my_task", category = MyCategory.class, index = 100)
public class MyTask extends Task<MyTaskMetadata, MyParameter, MyResult> implements FlowElementCloser {

    private String customProperty;

    public MyTask(ElementContext context) {
        super(context);
        context.addFlowElementCloser(this);
    }

    @Override
    public MyResult execute(MyParameter parameter) throws FlowExecutionException {

        System.out.println(parameter.getStringParameter());

        MyResult result = new MyResult();
        result.setMessage("hello world.");
        return result;
    }

    @Override
    public void close() {
        System.out.println("closed.");
    }

    public String getCustomProperty() {
        return customProperty;
    }

    public void setCustomProperty(String customProperty) {
        this.customProperty = customProperty;
    }
}
  • コンストラクタ内で addFlowElementCloser メソッドを呼び出し自身のインスタンスを FlowElementCloser として登録しています。
  • FlowElementCloser インタフェースの持つ close メソッドを実装しています。