4.3 プロセスモデル

4.3.1 条件分岐

今までに説明してきたフローは、すべて一筋の流れが最初から最後まで枝分かれすることのないものでした。しかし当然のことですが、ASTERIAでは処理を分岐させて、複数の流れを使って処理を実行することもできます。ここでは、条件判断をして処理を分岐する「ブランチ」の方法についてご説明します。

条件判断をして処理を分岐するには、「ブランチ開始」(BranchStart)コンポーネントを使います。BranchStartコンポーネントは、サービスパレットの「Branch」タブに入っています。

サービスパレットのBranchタブには他にもブランチを開始するためのコンポーネントがありますが、ここでは最も基本となるBranchStartコンポーネントのみ取り上げます。

BranchStartコンポーネントは出力コネクタを2つ持っています(右と下)。2つのコネクタに出力されるストリームの内容は同じです。フローの実行時に、条件が満たされていた(True)ならば右へ、満たされていない(False)ならば下へ処理が進みます。

条件式は、Conditionプロパティに設定します。

BranchStart
Condition $flow.flag = 0

条件式の書き方は、「RQL」「MQL」「XPath」の3種類があります。ここでは最も基本となる「RQL」の書き方を覚えましょう。「RQL」という改まった名前がついているので難しそうに思うかもしれませんが、内容は簡単です。

MQLはMIME形式のストリームを処理する場合、XPathはXML形式のストリームを処理する場合にのみ使用します。 それ以外はRQLを用いて条件式を書きます。 MQLとXPathの使い方については、BranchStartコンポーネントのヘルプを参照してください。

RQLでは、ストリームのフィールドの値や各種変数・定数の値、固定値を条件式の中に入れることができます。書き方とその例を、一覧で見てみましょう。

変数等の種類書き方
フィールドを持つストリームのフィールド
(フィールド名で指定)
record.<フィールド名>record.KEY_DATA = "001"
フィールドを持つストリームのフィールド
(フィールドインデックス番号で指定)
record[n] record[3] >= 0 (record[3]は4番目のフィールドを指す)
フィールドを持たないストリームの内容record.Objectrecord.Object ~= "ASTERIA"
フロー変数$flow.<変数名>$flow.bunki_flg = 0
セッション変数$session.<変数名>$session.data_count < 10
プロジェクト定数$project.<変数名>record.VersionNo = $project.VERSION_NO
システム変数$system.<変数名>$system.ExceptionMessage != ""

「フィールドを持たないストリーム」とは、「Text」「HTML」「Binary」「MIME」を指しています。

2番目の例のようにフィールドのインデックス番号で指定する場合、インデックス番号は0始まりとなります。よって、1番目のフィールドがrecord[0]、2番目がrecord[1]…となります。

左辺と右辺の値を比較する「=」や「>」などの記号は、比較演算子と呼びます。 ASTERIAで使うことのできる比較演算子は次の通りです。

比較演算子意味備考
=等しい
!=等しくない
>左辺が右辺より大きい右辺が数値の場合のみ
<左辺が右辺より小さい右辺が数値の場合のみ
>=左辺が右辺以上右辺が数値の場合のみ
<=左辺が右辺以下右辺が数値の場合のみ
~=左辺の文字列中に右辺の文字列を含む右辺が文字列の場合のみ

他のプログラム言語に詳しい方へ:「等しいかどうか」の比較演算子は、「==」ではなく「=」です。

では、実際のフローでBranchStartの動作を見てみましょう。 「431_Process_Branch.xfp」に入っている「ブランチ1」フローを開いてください。

このフローでは、現在時刻から秒の値を取り出し、その値が偶数か奇数かを計算してフロー変数"flag"に代入しています。そして、代入された値が0かどうかをブランチで判断しています。最後に、判断結果をテキストで出力します。

MOD関数は「剰余」(割り算の余り)を計算する関数です。ここでは「秒 / 2」の余りを計算しています。

BranchStartコンポーネントでは、次のように条件式が設定されています。 この条件式は「フロー変数"flag"の値が0であるか?」という意味です。

BranchStart
Condition $flow.flag = 0

続くマッパーでは、偶数の場合と奇数の場合それぞれでテキストストリームにメッセージを出力しています。

実行ダイアログから実行すると、時刻の秒が偶数か奇数かで表示されるメッセージが変わります。 両方のパターンが出るまで、何度か繰り返し実行してみてください。

また、一度ブランチで分岐したフローを、再び1本のフローにまとめなおすこともできます。そのときは、「ブランチ終了」(BranchEnd)コンポーネントを使います。BranchEndコンポーネントも、サービスパレットの「Branch」タブに入っています。

「431_Process_Branch.xfp」の「ブランチ2」フローで確認してみましょう。

このフローの前半の処理は「ブランチ1」と同じです(条件式も「$flow.flag = 0」です)。 後半部分が違います。 「ブランチ2」では、「奇数ですね。」と「偶数ですね。」の文字列をフロー変数「message」に代入します。その後BranchEndコンポーネントでフローを1本に戻し、最後にフロー変数「message」からテキストストリームを経由してメッセージを出力しています。

実行結果は「ブランチ1」フローと同様になります。

BranchEndコンポーネントはストリームを通過させない仕様となっています。従って、BranchEndより前で生成されたデータをBranchEndより後ろで使いたい場合は、今回のように変数を経由してデータを伝達するなどの工夫が必要になります。

4.3.2 パラレル

分岐ではなく、複数の処理を並行して行いたい場合には、特別なコンポーネントは必要ありません。あるコンポーネントの出力から矢印を2本以上引けば、自動的にパラレル処理になります。

ただし、パラレル処理は「並行して処理する」といいつつも、実は同時実行されるわけではありません。あらかじめ決めておいた順番で処理が実行されます。

あくまでフローはシングルスレッドで処理されるということです。マルチスレッド処理としたい場合は、Timerコンポーネントを用いて明示的に別スレッドでフローを実行します。

では、実際のフローでパラレル処理の動作を見てみましょう。 「432_Process_Parallel.xfp」に入っている「パラレル1」フローを開いてください。

このフローでは、「品番, 品名, 価格」の3カラムを持つCSVファイルを読み込み、それを「品番, 品名」の2カラムのCSVファイルと、「品番, 価格」の2カラムのCSVファイルへ書き出すという処理をしています。

実行すると、「output_data」フォルダに「Parallel1.txt」「Parallel2.txt」の2つのファイルが生成されます。

このように、パラレル処理はとても簡単に実現できます。

もちろん、フローの一部分だけをパラレル処理にして、再び1つのフローにまとめることもできます。その場合、パラレル処理している部分から流れてきたストリームを使うか使わないかによって、方法が異なります。

  • ストリームデータを使う場合、Controlタブの「パラレル終了」(ParallelFilterEnd)コンポーネントを使います。
  • ストリームデータを使わない場合(単純にフローを1本にまとめるだけの場合)は、コンポーネントは不要です。マッパーなど、複数の矢印を接続できるコンポーネントにつないでください。

ParallelFilterEndを使う場合と使わない場合の違いは、下記のようにしてマッパーを開いて比較するとよくわかります。「432_Process_Parallel.xfp」の「パラレル2」フローと「パラレル3」フローを開いてください。

この2つのフローは、パラレル処理をしている部分のFileSystem(Get)で2種類のCSVファイルを読み込み、ストリームに出力している点は同じです。

2つのフローで異なる部分は、ParallelFilterEndコンポーネントと、パラレル処理が終了した後のマッパーです。 「パラレル2」フローでは、パラレル処理終了時にParallelFilterEndコンポーネントを用いています。このコンポーネントを使うと次のように、マッパー内で複数のストリームの内容を同時に参照することができるようになります。

一方「パラレル3」フローのように、ParallelFilterEndを使わずにパラレル処理を終了すると、フローは正常に動作しますが、パラレル部分からのストリームを参照することはできません。

まとめると、パラレル部分で生成されたストリームをパラレル終了後のストリームに出力できるかどうかについて、次のように言えます。

     
  • 「パラレル2」フローでは、ParallelFilterEndを使用しているので、出力できる。
  •  
  • 「パラレル3」フローでは、ParallelFilterEndを使用していないので、出力できない。

それぞれのフローを実行すると、次のようになります。

パラレル2:

パラレル3:

パラレルが開始する直前のコンポーネントで右クリックメニューを表示すると「出力順序の並べ替え」という項目があり、そこでパラレル処理の実行順を設定できます。

メニューを選択すると、現在の出力順が矢印の上数字で表示されます。

数字をクリックすると、その順に実行順が設定されます。

ただし原則的には、パラレルの実行順に依存するフローにはしないほうが安全です。なるべくフローの見通しは良くして、思わぬ不具合を招かないようにしましょう。

なお、パラレル処理の順番については、ASTERIA Users Guideの「4.11.2. フロー種別ごとのコンポーネントの実行順序」もあわせてご覧ください。

4.3.3 ループ

ここでは、ループの有無による処理内容の違いと、使い分けのヒントをお教えします。

(1) ループとは

ASTERIAでは、複数件のデータを処理する場合、それらを一括で処理する方法と、1件ずつに分解してループを回して処理する方法の2種類があります。前者を「ループしないで処理」「LoopProcess=False」「PackRecord=True」、後者を「ループで処理」「LoopProcess=True」「PackRecord=False」 のように呼びます。

それぞれの場合のデータの扱われ方を模式図であらわすと、次のようになります。

ループしない場合:
 全件ひとかたまりのまま処理されます。

ループする場合:
 1件ずつバラバラに処理されます。

より実践的なフローを作る上では、ループするかしないかの使い分けは重要な項目です。特に、

  • レコードごとに後続の処理を変えたい
  • データサイズが大きい
このような場合にはループ処理にする必要があります。使い分けのヒントは、後述します。

(2) ループ有無による処理内容の違い

たとえば、次のようなフローを例とします。433_Process_Loop.xfpを開いてください。「ループなし」「ループあり」の2つのフローが入っています。

ここで使用しているサンプルフローでは、MS-AccessのmdbファイルをRDBとして使用しています。その関係上、StartコンポーネントのBeginTransactionプロパティをTrueに設定しています。これは、BeginTransactionがFalseの場合Accessの仕様により、データ取得処理ができないための措置です。

ともに、RDBからデータを読み込んで、CSV形式に変換してファイルに書き出すフローです。

両者の違いは、RDB_Getでループ処理をしているかいないかです。

RDB_Getでループを開始しない場合(LoopProcess=Falseの場合)、次のように処理が進みます。

RDB_GetでN件のデータが取得される

MapperでN件すべてマッピングされる

FilePutでN件すべてファイルに書き込まれる

EndResponseで終了

一方、RDB_Getでループを開始する場合(LoopProcess=Trueの場合)、次のように処理が進みます。

RDB_GetでN件中1件目のデータが取得される

その1件がMapperでマッピングされる

FilePutでその1件がファイルに書き込まれる

EndResponseコンポーネントに到達したら、まだ(N-1)件が未処理で残っているので最初に戻る

  • -------

RDB_GetでN件中2件目のデータが取得される

その1件がMapperでマッピングされる

(中略)

EndResponseコンポーネントに到達したら、まだ(N-2)件が未処理で残っているので最初に戻る

  • -------

(中略)

  • -------

RDB_GetでN件中N件目のデータが取得される

(中略)

EndResponseコンポーネントに到達したら、もう未処理のデータは残っていないので、終了

ここでのポイントは、ループを開始すると、ループの終わりは必ずフロー終了系コンポーネント(End、EndResponse、Abort、Break)となるという点です。フローの途中まででループを止めて、それ以降をループせずに処理するということはできません。そのような処理をしたい場合は、サブフローを作ってその中でループを開始するようにします。

ところで、「ループあり」フローを実行すると実行ダイアログには次のような結果が表示されます。

これは、EndResponseに入力された、ループの最後の1件のデータだけが表示(レスポンス)されているためです。 これを全件表示するには、ループで1件ずつ入力されたデータを改めて蓄積する必要があります。 そのための設定がEndResponseコンポーネントの「PackRecords」プロパティです。

デフォルトでは「PackRecords=False」ですので、これを「PackRecords=True」にして実行してみましょう。するとこのように、ループしない場合と同様にデータを全件表示することができます。

同様のことはファイル書き出しの部分でも発生します。ループなしのフローでは全件分のデータが一度にファイルに書き出されますから、FileSystem(Get)コンポーネントが呼び出されるたびにファイルが上書きされるモード「AppendMode=New」で処理を実行できます。 しかし、ループありのフローでは1件分ずつファイルに書き出されますから、上書きではなく追記するモード「AppendMode=Append」でファイルを書き出す必要があります。もし「AppendMode=New」で処理すると、1件ごとにファイルが更新されてしまい、結果的に最後の1件分のデータしかファイルに残りません。

サンプルフローのデフォルトは、ループなしの場合は「AppendMode=New」、ループありの場合は「AppendMode=Append」に設定してあります。

この例ではRDBから読み込んだデータをループ処理しましたが、ファイルから読み込んだデータをループ処理することももちろん可能です。ただしその場合、FileSystem(Get)コンポーネントでファイルを読み込んでループを開始しても、1行ずつファイルを読み込むことはできません。それは、FileSystem(Get)のループは「複数のファイルを取得した場合に、1ファイルずつストリームに出力する」という意味になるからです。ファイルからの読み込みで1行ずつループしたい場合は、RecordGetコンポーネントを使用します。このコンポーネントを使ってループを開始すれば、1行ずつデータを処理できます。

(3) 使い分けのヒント

経験的には、ループする必要があるか、ループしたほうがより見通しがよくなる場合の方が多いです。

可能でしたら、ループしないで処理します。その方が、若干ですがパフォーマンスが良くなります。 ただし、次のような場合、ループする必要があります。

  • ストリームの値を変数やコンポーネントプロパティにマッピングする場合

 ストリームから変数等への値のマッピングは、マッパーが1回呼び出されるごとに1件分しか行われません。つまり、ループしない場合は全部でN件あるレコードの1件目の値しか変数に格納されないのです。これを避けるには、マッパーをN回呼び出す、すなわちループ処理にする必要があります。

変数に値をマッピングする場合でも、たとえば「ある数値型フィールドの、全レコードでのSUMをとってフロー変数に入れる」ような場合は、ループしなくても対応可能です。

  • ブランチ処理が入る場合

 1レコードごとにブランチで処理を分岐させたい場合、ループ処理にする必要があります。ループしない場合、全件ひとかたまりで分岐することしかできません。

  • 取得するデータの容量が大きい場合

 ループしないでデータを読み込むと、全てのデータが一度にメモリ内に展開されます。そのため、データ量が大きい場合はメモリ容量をオーバーしてしまい、OutOfMemoryエラーとなる可能性があります。ループ処理にすれば、1件ごとにメモリに展開されますので、データ量の影響を受けにくくなります。

ASTERIAでは、データがメモリに展開されるとき、実データの10〜40倍程度の容量となります。よって、ループしないで処理できる実データ容量の限界値は(最大メモリサイズの設定にもよりますが)およそ10MB〜50MBとなります。

4.3.4 サブフロー

サブフローは、別のフローから呼び出されるフローを指すASTERIA用語です。

一方、サブフローを呼び出す側のフローは「呼び出し元フロー」といいます。「親フロー」「メインフロー」と呼ぶこともあります。

従来のプログラミング言語ではサブルーチンやユーザ関数という形で、共通的な処理を切り出してひとつにまとめたり、全体の見通しを良くする手法が実現されていました。ASTERIAでは、「サブフロー」を用いて処理の切り出しや共通化をすることができます。

それではさっそく、実際にフローを作りながらサブフローの使い方を見てみましょう。

(1) 準備

あらかじめある程度の準備を施したプロジェクトファイルを用意してあります。プロジェクト「434_Process_SubFlow.xfp」を開いてください。

このプロジェクトには、「ファイル書き出し1」「ファイル書き出し2」「ファイル書き出し3」「ファイル読み込み」というフローがすでに入っています。このあと、これらのフローをサブフローとして使います。

サブフローは、あくまでフロー間の相対的な親子関係の中での、「子」にあたるフローの呼び方です。特別に「サブフロー」という種類のフローをつくるわけではありません。あるひとつのフローが、あるフローからはサブフローとして呼び出され、一方では他のフローをサブフローとして呼び出す、ということも可能です。また、複数の別のフローから、同じフローがサブフローとして呼ばれるような構造にもできます。

余談ですが、実は昔のASTERIAでは「サブフロー」という種類のフローを作る必要がありました。

(2) サブフローを呼び出す

最初の例は、単純にサブフローを呼び出すだけの処理です。呼び出し元フローとサブフローの間でのデータの受け渡しはありません。

ここでは、「ファイル書き出し1」フローをサブフローとして呼び出す、呼び出し元フローを作ってみましょう。なお「ファイル書き出し1」フローは、「フローの実行日時を、ファイル名"SubFlow1.txt"で、"output_data"フォルダに、テキストファイルで書き出す。」という処理内容になっています。フロー変数は1つもありません。

まず、プロジェクト「SubFlow」(434_Process_SubFlow.xfp)の中に、新規フローを1つ作成してください。フロー名は「呼び出し元1」としましょう。

つづいて、左のサーバリストから「ファイル書き出し1」フローを、「呼び出し元1」フローのフローウインドウ内にドラッグ&ドロップします。

このように、呼び出し元フローから見ると、サブフローは1つのアイコンに見えます。

Endコンポーネントも配置し、矢印で連結すれば、サブフロー呼び出しの完成です。

それでは、「呼び出し元1」フローをASTERIAデザイナから実行してください。実行終了後に「output_data」フォルダを見ると「SubFlow1.txt」ができています。 これで、「呼び出し元1」フローから「ファイル書き出し1」フローが呼び出されて実行されたことがわかります。

(3) サブフローにストリームデータを渡す

2つめの例は、呼び出し元フローからサブフローにストリームデータを渡す処理です。

ここでは、呼び出し元フローで生成されたテキストストリームをサブフローに渡して、サブフロー側でファイルに書き込む処理をします。

サブフローとして呼び出す「ファイル書き出し2」フローは、「呼び出し元フローから渡されたテキストストリームを、"SubFlow2.txt"のファイル名で、"output_data"フォルダに、テキストファイルで保存する」という処理内容になっています。フロー変数はありません。

「ファイル書き出し2」フローのポイントは、Startコンポーネントに次の設定がされている点です。

Start
OutputStreamFormat Text
Encoding Windows-31J

この設定により、呼び出し元フローから渡されたテキストストリームを、サブフロー内で扱うことができるようになります。

では、プロジェクト「SubFlow」(434_Process_SubFlow.xfp)の中に、新規フローを1つ作成してください。フロー名は「呼び出し元2」としましょう。さらに、左のサーバリストから「ファイル書き出し2」フローを、「呼び出し元2」フローのフローウインドウ内にドラッグ&ドロップします。

この例では呼び出し元フローからサブフローに、テキストストリームを渡す必要があります。マッパーを1つ配置してください。そして、矢印で連結しましょう。

これでフローの骨格はできあがりました。

つづいてマッパーのプロパティを設定します。 ここでポイントとなるのは、サブフローにストリームを渡す場合は、サブフローに流し込むストリームの型やプロパティと、サブフローのStartコンポーネントのストリームの型やプロパティが一致している必要があるという点です。

電気のコンセントやヘッドホンのプラグ/ジャックと同じように、つなぐ部分はぴったりはまるように作る必要があるわけです。

ここでは呼び出すサブフローのStartコンポーネントに、マッパーの設定を合わせる必要があります。ここでは、OutputStreamFormatをデフォルトのParameterListからTextに変更し、Encodingをデフォルトのutf-8からWindows-31Jに変更します。

Mapper
OutputStreamFormat Text
Encoding Windows-31J

さらに、マッパー内のマッパー関数も配置してしまいましょう。 中身は次のようにしてください。

これで、「呼び出し元2」フローが完成しました。ASTERIAデザイナから実行すると、「output_data」フォルダに「SubFlow2.txt」が作成されます。

確かに、呼び出し元フローから渡した値(フロー実行時刻)がファイルに書き出されていることがわかります。

親フロー側にサブフローコンポーネントを配置(ドラッグ&ドロップ)した後にサブフロー側でフロー変数を追加・変更・削除した場合は、親フロー側のサブフローコンポーネントで右クリックし「フィールド定義を更新」してください。

(4) サブフローにパラメータを渡す

今度は、サブフローにパラメータを渡す例を見てみましょう。

ここでは、2つめの例と同様に、呼び出し元フローで生成されたテキストストリームをサブフローに渡して、サブフロー側でファイルに書き込む処理をします。ただし、ここでは書き込むファイル名も呼び出し元フロー側で設定し、サブフロー側へパラメータとして渡すようにします。

サブフローとして呼び出す「ファイル書き出し3」フローは、「呼び出し元フローから渡されたテキストストリームを、フロー変数"file_path"の内容をフォルダ・ファイル名に用いて、テキストファイルで保存する」という処理内容になっています。

それでは、サブフローのフロー変数"file_path"には、どのようにして呼び出し元フローから値を渡すのでしょうか。

その答えは「コンポーネントプロパティ」です。サブフロー内で用意したフロー変数は、呼び出し元フローから見るとコンポーネントプロパティの一部として見え、読み書きできるようになっているのです。ですのでここの例では、サブフローのフロー変数"file_path"は、呼び出し元フローからはサブフローコンポーネントのコンポーネントプロパティ"file_path"として見ることができ、値を読み書きすることができます。

では、プロジェクト「SubFlow」(434_Process_SubFlow.xfp)の中に、新規フローを1つ作成してください。フロー名は「呼び出し元3」としましょう。さらに、左のサーバリストから「ファイル書き出し3」フローを、「呼び出し元3」フローのフローウインドウ内にドラッグ&ドロップします。

呼び出し元フローの骨格は、2つめの例と同じですので、マッパーとEndを1つ配置しましょう。そして、矢印で連結してください。

つづいてマッパーのプロパティを設定します。マッパーの右クリックメニューから、「サブフローのフィールド定義をインポート」をしてください。

これは先ほどと操作手順が違います。 実は、右クリックメニューから「サブフローのフィールド定義をインポート」をすると、サブフロー側のStartコンポーネントに設定されたフィールド定義とストリームプロパティを、呼び出し元フロー側のコンポーネントに取り込むことができるのです。

ストリームのフィールド数が多い場合などは、この方法を使うのが便利です。先ほどは、基本的な仕組みを理解していただくためにあえて手作業で設定しましたが、ここからは簡単・確実なこちらの方法を使うことをおすすめします。

話を戻して、マッパー内のマッパー関数を配置しましょう。 中身は次のようにしてください。

CONST関数の設定は次の通りです。

CONST
Data output_data/SubFlow3.txt

これで、「呼び出し元3」フローが完成しました。ASTERIAデザイナから実行すると、「output_data」フォルダに「SubFlow3.txt」が作成されます。

設定通りに、ファイルに書き出されていることがわかります。

このほか、「サブフローのStartコンポーネントのArgumentに、呼び出し元フローのフロー変数と同じ名前の引数を設定して、サブフロー側で呼び出し元フローのフロー変数の内容を読み込む」という方法もあります。この方法は例外処理でよく使うパターンですので、具体例は「4.3.5 例外処理」をご覧ください。

(5) サブフローからストリームデータやパラメータを受け取る

もちろん、サブフローへデータを渡すだけでなく、サブフローからデータを受け取ることもできます。

方法はサブフローへデータを渡す場合と似ていますから、ストリームデータを受け取る方法とパラメータを受け取る方法をまとめて確認してみましょう。

ここでは、サブフローとして「ファイル読み込み」フローを呼び出します。このフローは、ストリームは次のように設定されたCSVストリームを出力します。

SubFlow
OutputStreamFormat CSV
FieldCount 3
Encoding Windows-31J

また、このフローは日時型のフロー変数"exec_datetime"に、フローが実行された時点の日時データを保存します。

では、プロジェクト「SubFlow」(434_Process_SubFlow.xfp)の中に、新規フローを1つ作成してください。フロー名は「呼び出し元4」としましょう。さらに、左のサーバリストから「ファイル読み込み」フローを、「呼び出し元4」フローのフローウインドウ内にドラッグ&ドロップします。

マッパーとVelocityコンポーネント、EndResponseコンポーネントを配置し、矢印で連結します。なお、Velocityコンポーネントは、CSVストリームの中身とコンポーネントプロパティの中身を一度に表示したいので、見た目の整形のために使用しています。

ここまでで、フローの骨格はできあがりました。つづいて、プロパティの設定です。

まず、サブフローコンポーネントの出力ストリームを次のように設定しましょう。これは、サブフローにストリームを渡す場合と同様に、ストリームの受け渡し部分では、呼び出し元フロー側とサブフロー側のストリームの型やプロパティを一致させておく必要があるからです。

SubFlow
OutputStreamFormat CSV
FieldCount 3
Encoding Windows-31J

Velocityコンポーネントは、次のように設定してください。

Velocity
TemplateFilename input_data/SubFlowResultTemplate.vm
OutputStreamFormat Text
Encoding Windows-31J

LocalVariablesタブ
NameType
ExecDateTimeDateTime

そして、マッパーは次のように設定します。

Mapper
StreamPassThrough True

さらに、次のようにマッピング設定をして、コンポーネントプロパティの内容を、Velocityコンポーネントのコンポーネント変数にコピーします。

なお、SubFlowResultTemplate.vmの中身は以下のようになっています。

ストリームの内容(CSV)
  • --------------------------------------------------------------------- #foreach( $rec in $in.records )
$rec.field1 $rec.field2 ¥$rec.field3
  • --------------------------------------------------------------------- #end
コンポーネントプロパティの内容
  • --------------------------------------------------------------------- $local.ExecDateTime

これでフローができあがりました。 実行すると、次のように表示されます。

サブフローからストリームとパラメータを受け取ることができたことがわかります。

4.3.5 例外処理

フローの実行中に発生するエラーを例外(Exception)と呼びます。

フロー実行中に例外が発生した場合、例外処理の設定を何もしていないと例外が起きた時点ですぐにフローが終了(異常終了)してしまいます。業務で使うフローなど、それでは困る場合は「例外フロー(Exceptionフロー)」を使ってエラーに対処する処理をあらかじめ書いておくことができます。

例:エラー内容をログに書き出す、エラー内容をメールで担当者に通知する、など。

例外処理のサンプルは、435_Process_Exception.xfpにあらかじめ用意してあります。

(1) 例外フローの呼び出しかた

435_Process_Exception.xfpに入っている、「通常処理1(例外処理あり)」フローを開いてください。

このフローは、テキストファイルを読み込んでレスポンスするようになっています。しかし、実はこのフローを実行すると例外が発生します。それは、FileSystem(Get)コンポーネントのFilePathプロパティに何も設定が入っていないからです。

「通常処理1(例外処理あり)」フローで例外が発生したときには、「例外処理1」フローが例外フローとして呼び出されるように設定されています(設定方法は後述)。この「例外処理1」フローは、いくつかのシステム変数から例外処理中にだけ設定されるデータを取得し、実行日時とともにCSVファイルに出力しています。

設定方法を見る前に、「通常処理1(例外処理あり)」フローをASTERIAデザイナから実行してみましょう。「ファイルが見つかりません」という例外が発生し、その内容がログファイル([HOME]/output_data/exception.txt)に書き出されます。

では、「通常処理1(例外処理あり)」フローと「例外処理1」フローは、どこの設定で関連付けられているのでしょうか。それは、「通常処理1(例外処理あり)」フローの、「Exception」プロパティです。

このプロパティは、次のようにして表示し、入力することができます。

1.「通常処理1(例外処理あり)」のフローを開きます。 2.つづいて、左側のサーバリストで、「通常処理1(例外処理あり)」の前にあるアイコンをクリックします。

3.すると、プロパティウインドウが次のようになります。

4.「Exception」プロパティをクリックすると、フロー一覧ウインドウが開きます。

5.一覧から、「例外処理1」を選択します。

なお、この手順で設定するプロパティはフロー全体に対するプロパティ設定ですので、そのフローに含まれるどのコンポーネントで例外が発生した場合でも、ここで設定されたExceptionフローが起動されます。

他に、「コンポーネントのExceptionプロパティで、個別に例外フローを設定する方法」もあります。両者は併用可能です。詳しくはASTERIA Users Guideの「4.10. Exceptionフロー」をご覧下さい。

(2) 例外フローへの変数値の渡しかた

先ほどの例では、通常処理フローから例外処理フローを呼び出しただけで、特にデータを渡すことはしていませんでした。しかし、実際にログ出力などを行なう場合は、たとえば取得データのキー項目など、任意の値をログに書き出したいという要求があります。

それを実現するには、次の方法を使います。

「通常処理2(例外処理あり)」フローを開いてください。このフローは先ほどの「通常処理1(例外処理あり)」フローとほぼ同じ内容です。

ただし、「フロー変数"exec_datetime"に実行日時を文字列型で代入している」という点が異なります。ここでは、最終的にはこのフロー変数の内容を例外処理フローに渡し、ログ出力することとします。

「通常処理2(例外処理あり)」からは、例外発生時に「例外処理2」フローが呼び出されるように設定されています。このフローは「例外処理1」フローとほぼ同じ内容です。

ただし、「StartコンポーネントのArgumentに"exec_datetime"という名前の引数を設定し、例外が発生したフローのフロー変数"exec_datetime"の値を読み込めるようにしている」点が異なります。

「通常処理2(例外処理あり)」フローを実行すると、次のようにログファイル([HOME]/output_data/exception.txt)に書き出されます。

(3) 参考:もし例外処理がなかったら

「通常処理0(例外処理なし)」フローは、「通常処理1(例外処理あり)」フローから、例外フローの設定をはずしたものです。このフローをASTERIAデザイナから実行すると、下図のようにエラーメッセージが直接画面に表示されます。