M230 自動工程
最終更新 2017年9月21日

業務データの複雑なデータ加工が自動実行されるように設定する(ECMAスクリプト)

スクリプト工程をフロー図の途中に配置すれば、データ編集の自動化を実現できます。例えば "出勤時刻" と "帰宅時刻" から勤務時間を算出すると言った演算処理や、 "作業実施日" の曜日情報を自動的に付加すると言った文字列編集処理を自動化する事ができます。([サービスタスク(データ設定)] より更に複雑な処理が可能です)

M230-1

1. データ代入
ECMA スクリプトで生成した日付や数値などを自動的に代入させる
2. データ加工
入力済みの数値や文字列を加工し、新たなデータとして代入する
  • “ECMA スクリプト”とは、JavaScript と JScript の共通部分をベースに標準化されたスクリプト言語です

a. 推奨される JavaScript
“ECMA-262, Edition 3” (JavaScript 1.5) に規定された全てのクラス
b. 利用可能な JavaScript
“ECMA-262, Edition 5” (JavaScript 1.7/1.8) の多くのクラス
c. 利用可能な Java クラス
業務データへのアクセスに必要な Java クラス、他
  • JavaScript と Java の基礎的な知識が必要になります

R2300 スクリプトタスクで利用できる Java クラス

1. ECMA コードを登録する
データ参照、データ加工、データ代入などの処理コードを記入します
  • 業務データの代入や更新は、スクリプト処理完了後に一括して行われます
  • エラー発生時には代入更新は行われません (次の処理に進みます)
  • スクリプトの処理時間は最長で30秒に制限されます (負荷状況により若干変動します)
//// == Data Retrieving ==
var dataA = engine.findDataByNumber("0") + ""; // 業務データ0を参照
var dataB = engine.findDataByName("Data B") + ""; // 「Data B」という項目名の業務データを参照
// convert java.lang.String → javascript string

//// == Calculating ==
var newData = dataA + dataB;

//// == Data Updating ==
engine.setDataByNumber("3", newData ); //業務データ代入

R2301 Scriptデータ取得/代入

R2252 OAuth トークン取得手順

M230-2




a. Rhino エンジン
[スクリプト工程]は、スクリプト実行エンジン “Rhino” (ライノゥ/原意:動物のサイ)によって処理されます。(サーバーサイド)
b. Rhino の特徴
プロセスモデル設計者は “ECMAScript” (JavaScript) による自動処理スクリプトだけでなく “Java メソッド” による自動処理スクリプトも設定できます(Scripting Java)。たとえば new java.lang.String("kyoto") のような書式でオブジェクトを生成すれば、 replaceFirst() といった Java String クラスのメソッドが使用できるようになります。
c. ワークフローに流れるデータの参照
“請求日” や “見積額” といった業務データを参照するには、特別なメソッド data.get("♦項目ID♦") を利用します。Java インスタンスとして呼び出されるため JavaScript string/object として扱う場合は var text = data.get("♦項目ID♦") + ""; などの明示的な型変換が推奨されます。

/// TYPEOF test - for Rhino ECMA engine

var workflowData = data.get("0") ;

var teststring = ""; 

  teststring += "-- primitive Number -- \n"; 
  teststring += typeof 99        + "\n"; // 'number'
  teststring += typeof 9.99      + "\n";
  teststring += typeof Infinity  + "\n";
  teststring += typeof NaN       + "\n";
  teststring += typeof Number(9) + "\n";

  teststring += "-- primitive String -- \n"; 
  teststring += typeof ""             + "\n"; // 'string'
  teststring += typeof "Questetra"    + "\n";
  teststring += typeof (typeof 99)    + "\n";
  teststring += typeof String("ECMA") + "\n";

  teststring += "-- Object -- \n"; 
  teststring += typeof new Number(9)                + "\n"; // 'object'
  teststring += typeof new String("ECMA")           + "\n";
  teststring += typeof new java.lang.String("ECMA") + "\n";
  teststring += typeof workflowData                 + "\n";
  teststring += typeof data.get("0")                + "\n";
  teststring += typeof new com.questetra.bpms.core.model.formdata.ListArray() + "\n";

  teststring += "-- XML -- \n"; 
  teststring += typeof <foo bar="BAR">FOO</foo>            + "\n"; // 'xml'
  teststring += typeof XML('<foo bar="BAR">FOO</foo>')     + "\n";
  teststring += typeof new XML('<foo bar="BAR">FOO</foo>') + "\n";

  teststring += "--- additional info --- \n"; 
  teststring += typeof true + "\n";          // 'boolean'
  teststring += typeof undefined + "\n";     // 'undefined'
  teststring += typeof [1, 2, 4] + "\n";     // 'object'
  teststring += typeof /s/ + "\n";           // 'object'
  teststring += typeof null + "\n";          // 'object' (not 'null')
  teststring += typeof function(){} + "\n";  // 'function'
//  teststring += typeof Symbol() + "\n";    // ERROR (not 'symbol')

retVal.put( "0", teststring );

testX <- String("BPMS")
testX is NOT instanceof String
testX is NOT instanceof java.lang.String

testY <- new String("ECMA")
testY is instanceof String
testY is NOT instanceof java.lang.String

testZ <- new java.lang.String("JAVA")
testZ is instanceof String
testZ is instanceof java.lang.String

test1 <- data.get( "8" )
test1 is instanceof String
test1 is instanceof java.lang.String

test1b <- data.get( "8" ) + ""
test1b is NOT instanceof String
test1b is NOT instanceof java.lang.String

test2 <- data.get( "9" ) // Select
test2 is NOT instanceof String
test2 is NOT instanceof java.lang.String
test2 is instanceof java.util.ArrayList

d. ワークフローに流れるデータの更新
スクリプト工程にて演算された値を、ワークフローに流れる業務データとして代入するには、特殊なメソッド retVal.put("♦項目ID♦","♦新しい値♦") を利用します。(ECMA/JavaScript には数値に関する型が "number型" しか存在しないため、スクリプト内で演算された結果をワークフロー側に戻す際に "java.math.BigDecimal" を明示的に記述する必要があります)
e. 業務に役立つ関数およびサンプルコード

//////// == 演算 / Calculating ==
var myrand = Math.floor( Math.random() * 5 ) ; // 0 or 1 or 2 or 3 or 4

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", java.math.BigDecimal(myrand) );

//// == ワークフローデータの参照 / Retrieving ==
var timestart = data.get("♦DataDefID♦"); // 日時型:プロセス開始時刻
var timesent = data.get("♦DataDefID♦"); // 日時型:回答メール送信時刻

//// == 演算 / Calculating ==
var conciergesec = timesent.getTime() - timestart.getTime();
var conciergehour = java.math.BigDecimal( Math.floor( conciergesec / (1000 * 60 * 60) )); // Math.floor 切り捨て

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦",conciergehour);

var daystart = timestart.getDay(); // 問い合わせ発生曜日のメモ
if (daystart == 0) retVal.put("♦DataDefID♦","日曜日");
if (daystart == 1) retVal.put("♦DataDefID♦","月曜日");
if (daystart == 2) retVal.put("♦DataDefID♦","火曜日");
if (daystart == 3) retVal.put("♦DataDefID♦","水曜日");
if (daystart == 4) retVal.put("♦DataDefID♦","木曜日");
if (daystart == 5) retVal.put("♦DataDefID♦","金曜日");
if (daystart == 6) retVal.put("♦DataDefID♦","土曜日");

//// == ワークフローデータの参照 / Retrieving ==
var mynumber = data.get("♦DataDefID♦") + ""; 

//// == 演算 / Calculating ==
if( mynumber.length == 13 ){
    var mysum = 0;
    for( i=1; i<13; i++){
       mysum += parseInt( mynumber.charAt(i) ) *  (i % 2 + 1);
    }
    var checkdigitnum = 9 - mysum % 9;
    var typedcd = parseInt( mynumber.charAt(0) );

//// == ワークフローデータへの代入 / Updating ==
    if( typedcd == checkdigitnum ){
       retVal.put("♦DataDefID♦", "OK" ); 
    } else {
       retVal.put("♦DataDefID♦", "ERROR" ); 
    }
}

//// == ワークフローデータの参照 / Retrieving ==
var weatherjson = JSON.parse(data.get("♦DataDefID♦")); // 中間イベント等で取得済の想定

//// == 演算 / Calculating ==
var mydesc = weatherjson.list[0].weather[0].description;
var mytemp = java.math.BigDecimal(weatherjson.list[0].temp.max - 273.15); 

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", mydesc );
retVal.put("♦DataDefID♦", mytemp );

//// == ワークフローデータの参照 / Retrieving ==
var fromaddr = data.get("♦DataDefID♦") + "";
var inq = data.get("♦DataDefID♦") + "";

//// == 演算 / Calculating ==
var inquirywithmark = inq.replace(/(^.*$)/gm, "> "+"$1"); // 行頭リダイレクトマーク

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", fromaddr + '\n' + inquirywithmark ); 

//////// == ワークフローデータの参照 / Retrieving ==
var csv_text = data.get("♦DataDefID♦");  // 文字列型複数行のCSVデータ(4列)を前提
// ex)
// Nakagyo-ku, Kyoto-shi, Kyoto-pref, Japan
// Malibu, Los Angeles County, California, USA

//// == 演算 / Calculating ==
var csvObj = new String( csv_text ); // String オブジェクト (JavaScript)
var tmpTable = new com.questetra.bpms.core.model.formdata.ListArray(); // テーブル型データ
var lineArray = csvObj.split("\n");  // 改行毎に分割し String[] 配列に格納
for (var i=0; i < lineArray.length; i++){
        var tmpRow = new com.questetra.bpms.core.model.formdata.ListArray.ListRow(); // 追加行(横列)
        var cellstrArray = lineArray[i].split(",");  // カンマ毎に分割し格納
        tmpRow.addCol( cellstrArray[0] );
        tmpRow.addCol( cellstrArray[1] );
        tmpRow.addCol( cellstrArray[2] );
        tmpRow.addCol( cellstrArray[3] );
        tmpTable.addRow( tmpRow );  // 行追加      
}

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", tmpTable );

//// == ワークフローデータの参照 / Retrieving ==
// mytable: com.questetra.bpms.core.model.formdata.ListArray
var mytable = data.get("♦DataDefID♦"); // テーブル型データを取得

//// == 演算 / Calculating ==
var i=0;
var n = mytable.size();
var texttsv = "";
for (i=0; i < n; i++){
  texttsv += mytable.get(i, 0) + "\t";
  texttsv += mytable.get(i, 1) + "\t";
  texttsv += mytable.get(i, 3) + "\t";
  texttsv += mytable.get(i, 4) + "\n";
}

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", texttsv ); 

//// == ワークフローデータの参照 / Retrieving ==
var quserEmail = data.get("♦DataDefID♦") + ""; // 文字列データに "example@example.net" が格納されている前提

//// == 演算 / Calculating ==
// com.questetra.bpms.core.event.scripttask.QuserDaoWrapper
var quser = quserDao.findByEmail(quserEmail);

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", quser);

//// == ワークフローデータの参照 / Retrieving ==
optionsList = itemDao.findAll("value-display-list.xml", true); // M319 Options-XML

//// == 演算 / Calculating ==
optionsNum = optionsList.size();
var value_id_list = "";
var display_label_list = "";
for (i=0; i < optionsNum; i++){
  value_id_list += optionsList.get(i).getValue() + "\n";
  display_label_list += optionsList.get(i).getDisplay() + "\n";
}

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", value_id_list);
retVal.put("♦DataDefID♦", display_label_list);

//// == ワークフローデータの参照 / Retrieving ==
optionsList = itemDao.findAll("value-display-list.xml", true); // M319 Options-XML

//// == 演算 / Calculating ==
var tmpTable = new com.questetra.bpms.core.model.formdata.ListArray(); // テーブル型データ
optionsNum = optionsList.size();
for (i=0; i < optionsNum; i++){
  var tmpRow = new com.questetra.bpms.core.model.formdata.ListArray.ListRow(); // 追加行(横列)
  tmpRow.addCol( optionsList.get(i).getValue() );
  tmpRow.addCol( optionsList.get(i).getDisplay() );
  tmpTable.addRow( tmpRow ); // 行追加
}

//// == ワークフローデータへの代入 / Updating ==
retVal.put("♦DataDefID♦", tmpTable );