public void testNomalOrderTx()

の中身・・・

orderBao.xpdl フロー情報をファイルから読み込み

61:// 本当はburi2.diconに書くもの
62:buriEngine_.getWorkflows().readWorkFlowFromResource("注文管理","orderBao.xpdl");

顧客情報と商品情報の準備

64:customerSetup();
65:itemSetup();

情報取得コレクション

66:List datas = null;

注文情報の準備

67:OrderInfoDto orderInfoDto1 = orderSetup1();

客1が商品2と商品3を注文情報にセット

注文する

69:orderBao_.order(orderInfoDto1);

これでワークフローにDtoを登録したことになり、注文フローが開始される。

 XPDL の 注文 Activity(order_Wor1_Act1)の Finish mode は Automatic なので、
 注文 → 出荷作業中 Transition(order_Wor1_Tra1)にしたがって、
 出荷作業中 Activity(order_Wor1_Act2)にステータスが変わる(変移する)

OrderBao インターフェースの PROCESS アノテーション

public static String PROCESS = "注文管理.注文";

 Paticipant は、顧客

 注文する:OrderBao インターフェースの以下メソッドを使う

public static String order_ACTIVITYVALIDATE = "注文";
public void order(OrderInfoDto dto);

 _ACTIVITYVALIDATE ってアノテーションあったっけ??
 …まぁあとで探してみよう。*1
 OrderInfoDto は long変数:orderTitleID があるので、BuriConvert が実行される。

→ OrderInfoDao.getOrderInfo(#data)

public OrderInfoDto getOrderInfo(long orderTitleID) {
    OrderTitleDto titleDto = titleDao.getOrderTitle(orderTitleID);
    if(titleDto==null) {
        return null;
    }
    OrderInfoDto info = new OrderInfoDto();
    info.setOrderTitleID(titleDto.getOrderTitleID());
    info.setCustomerID(titleDto.getCustomerID());
    info.setOrderDate(titleDto.getOrderDate());
    info.setStatus(titleDto.getStatus());
    List details = detailDao.getOrderDetailByTitleID(orderTitleID);
    info.setOrderDetail(details);
    return info;
}

 で、結局 OrderInfoDto で戻ってきて実行される。

以下追記 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

 「BuriConvertの変換元の型と一致しない場合は何もしませんよ」ってコメントなので、さっぱり理解してないとorz
 ちなみに CONVERTER はこうなってる。

OrderBao

public static BuriConvert CONVERTER = new BuriConvert{
    new BuriConvert(Long.class,"OrderInfoDao.getOrderInfo(#data)")
};

 さらに、「S2Buri入門記 6.Converter」をよく読むと…

要は、Baoの中に定義されているメソッドで、そのBaoが処理するべきDto以外のオブジェクトを引数として渡されたときに、そのオブジェクトをキーにして本来のDtoオブジェクトに変換するメソッドを呼び出すということね。

 って書いてあるじゃん^^;;
 そうすると、定義されているメソッドはこうだから

OrderBao(フロー処理用メソッド)

public static String order_ACTIVITYVALIDATE = "注文";
public void order(OrderInfoDto dto);

public static String endShipping_ACTIVITYVALIDATE = "出荷作業中";
public void endShipping(long orderID);
    
public static String endBill_ACTIVITYVALIDATE = "出荷終了";
public void endBill(long orderID);
    
public static String cancel_ACTIVITYVALIDATE = "出荷作業中,出荷終了";
public static String cancel_ACTION = "cancel";
public static String cancel_RESULT = "#cancelStatus";
public String cancel(long orderID);

 BuriConvert の第一引数の long に合致する

  • public void endShipping(long orderID);
  • public void endBill(long orderID);
  • public String cancel(long orderID);

 の3つのメソッドが BuriConvert で変換された Dto を使用する…(で、いいと思うんだがイマイチ不安だな^^;

ここまで −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

出荷作業中 のデータを取得する

70:datas = orderBao_.getUnderWork();

 Activity が 出荷作業中 のデータを検索する

  • OrderBao
public static String getUnderWork_ACTIVITY = "出荷作業中";
public List getUnderWork();

★ Baoのルール

・メソッド名
先頭がget/select/find/count
この場合、データ取得用のメソッドとして判断します。それ以外処理用メソッドとして判断します。

・戻り値
処理用メソッドでは何も制限がありません。

データ取得用のメソッドでは
・List
データの一覧用メソッドとして扱います。実際にはArrayListが戻ります
・Number型
データ数取得メソッドとして扱います。

データ一覧用メソッドでは
dataという名前の引数がなければselect/selectManyが利用され、データを取得します。
dataという名前の引数がある場合、findManyが利用されます。

データ数取得メソッドは
あるデータがいくつその状態にあるのかを判断するためのメソッドです。
その為、datasという名前のList型の引数が必須です。
#実際に使っているところはorderBao.xpdlの出荷の出荷準備中にあります


ex)
public List getUnderWork();
普通のデータ取得用のメソッドです。_ACTIVITYの指定が必須

★ Bao定数アノテーションリファレンス(の一部)

_ACTIVITY
メソッドと一緒に設定するアノテーション
取得系メソッドでは必須

対象になるActivity名を指定します

ex)
public static String getUnderWork_ACTIVITY = "出荷作業中";
この場合出荷作業中のデータを対象に処理します

検索結果のカウントが1であることをチェックする

71:assertEquals(datas.size(),1);
72:System.out.println(datas);

注文プロセスのつづき

出荷作業中 Activity(order_Wor1_Act2)の Finish mode は Manual なので、Toolを実行した後処理を停止する。
Tools を見ると[ id:order_App2 , Type:Applocation ]となってる。さらにダブルクリックすると Tool のプロパティが表示される。

  • id
    • AfterOgnlInvoker
  • Type
    • Application
  • Extended attributes
    • Name
      • ognl
    • Value
      • ShippingBao.shipping(#data)

AfterOgnlInvoker の説明を見ると

OgnlInvokerと同じです。
違いは、AfterOgnlInvokerをどこに書いたとしてもプロセスのすべての処理が終了した後に呼びだされます。

注意点としては、
・Context情報も終了直前のものが使われること
・複数回同じActivityを通ってそこにAfterOgnlInvokerが記述されている場合、複数回AfterOgnlInvokerを実行します

んーこれは、どっちが先なんだろ…*2

  1. Finish mode:Manual → Toolを実行した後処理を停止(‥だけど AfterOgnlInvoker が設定されてるからプロセスの停止が先)
  2. AfterOgnlInvoker:ShippingBao.shipping(#data) の実行(出荷プロセスの出荷依頼 Activity を実行する)

かな??

ShippingBao

ShippingBao インターフェースの PROCESS アノテーション

public static String PROCESS = "注文管理.出荷";

 Paticipant は、出荷担当者
 shipping メソッドで出荷プロセスをキックするってかんじかなぁ??

public void shipping(OrderInfoDto dto);

 BuriConvert がこうなってる場合はどうゆう風に処理されるんだろう。

public static BuriConvert CONVERTER = new BuriConvert{
    new BuriConvert(Long.class,"ShippingSetDao.getShippingSetDto(#data)")
    ,new BuriConvert(OrderInfoDto.class,"ShippingSetDao.getDtoByOrderTitleID(#data)")
};

OrderInfoDto は long変数:orderTitleID があるので、BuriConvert が実行される?
→ ShippingSetDao.getShippingSetDto(#data)

public ShippingSetDto getShippingSetDto(long shippingID) {
    ShippingSetDto setDto = new ShippingSetDto();
    ShippingDto dto = shippingDao.getShipping(shippingID);
    if(dto == null) {
        return setDto;
    }
    setDto.setShippingID(dto.getShippingID());
    setDto.setCustomerID(dto.getCustomerID());
    setDto.setOrderTitleID(dto.getOrderTitleID());
    setDto.setShippingDate(dto.getShippingDate());
    setDto.setShippingID(dto.getShippingID());
    setDto.setItems(itemDao.getShippingItemByShippingID(shippingID));
    return setDto;
}

で ShippingSetDto で戻ってくる。

OrderInfoDto そのものを引数として、BuriConvert が実行される?
→ ShippingSetDao.getDtoByOrderTitleID(#data)

public ShippingSetDto getDtoByOrderTitleID(OrderInfoDto orderInfo) {
    ShippingSetDto setDto = new ShippingSetDto();
    ShippingDto dto = shippingDao.getShippingByOrderTitleID(orderInfo.getOrderTitleID());
    if(dto == null) {
        setDto.setCustomerID(orderInfo.getCustomerID());
        setDto.setOrderTitleID(orderInfo.getOrderTitleID());
        Iterator ite = orderInfo.getOrderDetail().iterator();
        while(ite.hasNext()) {
            OrderDetailDto detailDto = (OrderDetailDto)ite.next();
            ShippingItemDto shippingItemDto = new ShippingItemDto();
            shippingItemDto.setOrderDetailID(detailDto.getOrderDetailID());
            setDto.getItems().add(shippingItemDto);
        }
        return setDto;
    }
    setDto = getShippingSetDto(dto.getShippingID());
    return setDto;
}

で ShippingSetDto で戻ってくる。

以下追記 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

 「一番目の引数が変換元、2番目が変換用のスクリプトです。
 変換元と型の一致をチェックしてヒットすればスクリプトを実行するってかんじです」
 とコメントされてるので…

new BuriConvert(Long.class,"ShippingSetDao.getShippingSetDto(#data)")

 引数が Long.class の場合は ShippingSetDao.getShippingSetDto(#data) を実行する。
 その結果は ShippingSetDto で戻ってくる。

public void checkEdnShipping(long shippingID);

 の場合はこっちになる。

new BuriConvert(OrderInfoDto.class,"ShippingSetDao.getDtoByOrderTitleID(#data)")

 引数が OrderInfoDto.class の場合は ShippingSetDao.getDtoByOrderTitleID(#data) を実行する。
 その結果は ShippingSetDto で戻ってくる。

public void shipping(OrderInfoDto dto);

public static String cancel_ACTION = "cancel";
public void cancel(OrderInfoDto dto);

 の場合はこっちになる。

 第一引数の型がどれにも当てはまらないならそのままスルー

 という風に第一引数の型で実行するメソッドを変更する…(でいいのかな?

ここまで −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

ShippingSetDto をもとに出荷プロセスを開始するってことでいいのかな。

PROCESS アノテーションが 出荷 になっているので、XPDL の出荷プロセスを見る

出荷依頼 Activity(order_Wor2_Act1) Finish mode は Automatic なので、
出荷依頼 → 出荷準備開始 Transition(order_Wor2_Tra1)にしたがって、
出荷準備開始 Activity(order_Wor2_Act2)にステータスが変わる(変移する)
その次に
出荷準備開始 Activity(order_Wor2_Act2) Finish mode は Automatic なので、Toolを実行した後処理を続行する。
Tools を見ると[ id:order_App2 , Type:Applocation ]となってる。さらにダブルクリックすると Tool のプロパティが表示される。

  • id
    • AfterOgnlInvoker
  • Type
    • Application
  • Extended attributes
    • Name
      • ognl
    • Value
      • ShippingItemBao.startShipping(#data.items)

あれ? AfterOgnlInvoker ってことは出荷のプロセス終わらないと実行されないのか??
‥と思ったら、次の商品待ち Activity(order_Wor2_Act9)の Finish mode は Manual だった。
それにToolsタブもないから、出荷プロセスはここで停止だ。
で、停止後に ShippingItemBao.startShipping(#data.items) が実行されると。

テストの部分

74:datas = shippingBao_.getNowWaiting();
75:assertEquals(datas.size(),1);
76:System.out.println(datas);

 getNowWaiting で商品待ちのデータを取得する

public static String getNowWaiting_ACTIVITY = "商品待ち";
public List getNowWaiting();

 検索結果のカウントが1であることをチェックする

ShippingItemBao

ShippingItemBao インターフェースの PROCESS アノテーション

public static String PROCESS = "注文管理.出荷詳細";

Paticipant は、出荷担当者

public void startShipping(ShippingItemDto dto);
public void startShipping(List dtos);

引数が #data.items の場合はどっちが実行されるんだ??
ふつうに考えると複数形の List のほうか。
まぁとにかく startShipping メソッドで出荷詳細プロセスがキックされる(と思う)

XPDL の出荷詳細プロセスを見る

商品準備開始 Activity(order_Wor5_Act1) Finish mode は Automatic なので、
商品準備開始 → 商品準備中 Transition(order_Wor5_Tra1)にしたがって、
商品準備中 Activity(order_Wor5_Act2)にステータスが変わる(変移する)
その次に
商品準備中 Activity(order_Wor5_Act2) Finish mode は Manual なので、処理を停止する。

テストの部分

78:datas = shippingItemBao_.getItemWaiting();
79:assertEquals(datas.size(),2);
80:System.out.println(datas);

getItemWaiting で商品準備中のデータを取得する

public static String getItemWaiting_ACTIVITY = "商品準備中";
public List getItemWaiting();

検索結果のカウントが2であることをチェックする*3

82:ShippingItemDto shippingItemDto = (ShippingItemDto)datas.get(0);

商品準備中の商品情報を1つ取り出す。ArrayListだと商品2のほうか?

85:shippingItemBao_.endShipping(shippingItemDto);

このメソッドで、出荷詳細プロセスが再開…なのかなぁ?
まぁユーザー(出荷担当者)からの入力になるところだなー。
ピッキングごとの入力かどうかわからないけど。

public void endShipping(ShippingItemDto dto);

で、商品準備中 Activity(order_Wor5_Act2)から Transition は2つある。

  • 商品準備中 → 商品準備完了 Transition(order_Wor5_Tra2)
  • 商品準備中 → cancel済み Transition(order_Wor5_Tra7)

Transition restriction をみると、Split type が Xor で、参照先の Activity 名称がエントリーされてる。
で、分岐の条件は何かと見てみると、

  • 商品準備中 → 商品準備完了
    • #action == null
  • 商品準備中 → cancel済み
    • #action == "cancel"

#action がない時と #action が "cancel" の時と。
出荷詳細プロセスのインターフェースの ShippingItemBao のこれだろう。

  • ShippingItemBao
public static String cancel_ACTION = "cancel";
public void cancel(ShippingItemDto dto);
public void cancel(List dtos);

と思ったら、ShippingBao にも OrderBao にもあるな…

  • ShippingBao
public static String cancel_ACTION = "cancel";
public void cancel(OrderInfoDto dto);
  • OrderBao
public static String cancel_ACTIVITYVALIDATE = "出荷作業中,出荷終了";
public static String cancel_ACTION = "cancel";
public static String cancel_RESULT = "#cancelStatus";
public String cancel(long orderID);

キャンセルは顧客が行うから、停止中の注文プロセスからキャンセルを OrderBao で実行すると、どうにかして他のプロセスに波及するはず……だけど、とりあえずそれは一旦置いておこう。*4

話を戻すと、#action がないので 商品準備中 → 商品準備完了 Transition(order_Wor5_Tra2)に従って、
商品準備完了 Activity(order_Wor5_Act3)にステータスが変わる(変移する)
その次に
商品準備完了 Activity(order_Wor5_Act3)の Finish mode は Manual なので、Toolを実行した後処理を停止する。
Tools を見ると[ id:order_App2 , Type:Applocation ]となってる。さらにダブルクリックすると Tool のプロパティが表示される。

  • id
    • AfterOgnlInvoker
  • Type
    • Application
  • Extended attributes
    • Name
      • ognl
    • Value
      • ShippingBao.checkEdnShipping(#data.shippingID)

で、出荷詳細プロセスが停止後に ShippingBao.checkEdnShipping(#data.shippingID) が実行されると。

ShippingBao が呼び出されたので 出荷プロセス に戻る

商品待ち Activity(order_Wor2_Act9)で停止してたはずなので、その続きから。
商品待ち → 出荷準備中 Transition(order_Wor2_Tra47)に従って、
出荷準備中 Activity(order_Wor2_Act8)にステータスが変わる(変移する)

その次に

出荷準備中 Activity(order_Wor2_Act8) Finish mode は Automatic なので、Toolを実行した後処理を続行する。
Tools を見ると[ id:order_App2 , Type:Applocation ]となってる。さらにダブルクリックすると Tool のプロパティが表示される。

  • id
    • AfterOgnlInvoker
  • Type
    • Application
  • Extended attributes
    • Name
      • ognl
    • Value
      • #countDatas = ShippingItemBao.getEndShippingCount(#data.items)
  • ShippingItemBao
public static String getEndShippingCount_ACTIVITY = "商品準備完了";
public static String getEndShippingCount_ARGS = "datas";
public long getEndShippingCount(List datas);

で、商品準備完了した商品のカウントを取得して #countDatas に代入すると。
Transition restriction をみると、Split type が Xor で、参照先の Activity 名称が3つある。

  • 出荷準備完了
  • 商品未揃い
  • 出荷キャンセル

分岐の条件は何かと見てみると、

  • 出荷準備中 → 出荷準備完了
    • #countDatas == #data.items.size() && #action == null
  • 出荷準備中 → 商品未揃い
    • #countDatas < #data.items.size() && #action == null
  • 出荷準備中 → 出荷キャンセル
    • #action == "cancel"

テストでは1つしか準備完了してない、キャンセルされてない、注文商品数は2なので、
出荷準備中 → 商品未揃い Transition(order_Wor2_Tra32)が成立する

商品未揃い Activity(order_Wor2_Act7)Finish mode は Automatic なので、処理を続行する。
で、なぜかこれだけ Performer がない、かつ、レーン(?)が別なとこにある。

商品未揃い → 商品待ち Transition(order_Wor2_Tra17)に従って、
商品待ち Activity(order_Wor2_Act9)に戻る。

条件が変わるまでループするのね。

あれれ?
だけどこれだと停止してる出荷詳細プロセスはどこで再開されるんだ??

以下追記 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

 「手動ですよBaoもあります」というコメント。
 出荷準備中 Activity(order_Wor2_Act8)の Tool

#countDatas = ShippingItemBao.getEndShippingCount(#data.items)

 が呼び出されたことで、出荷詳細プロセスは動いてるはずですね..orz
 で、フロー通りに進めば 商品準備中 Activity(order_Wor5_Act2)で入力待ちになるはず

ここまで −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

*1:「次のバージョンは実装からも消えます」との事なので気にしないでOK

*2:「その通りです」って事なのでOK

*3:orderSetup1()で商品2と商品3を注文情報にセットしてるから

*4:「キャンセルはOrderBaoからです。」という事で詳しくは testCancelSuccessOrderTx() のほうで追いかけよう