jBPM Suite関連Tips

※以下のTipsは jBPM Ver.6.0.1(コミュニティ版)で調査したものです

関連Web

タスクからタスク変数を参照する

 //このやり方で一応取得できるようですが、もっと簡単な方法がないのだろうか…
 public Map<String, Object> getTaskVariable(KieSession ksession,
                       TaskService taskService, TaskSummary task) {
   Task t = taskService.getTaskById(task.getId());
   TaskData td = t.getTaskData();
   long contentId = td.getDocumentContentId();
   Content content = taskService.getContentById(contentId);
   byte[] contBytes = content.getContent();
   Environment env = ksession.getEnvironment();
   @SuppressWarnings("unchecked")
   Map<String, Object> data = (Map<String, Object>) 
           ContentMarshallerHelper.unmarshall(contBytes,env);
   return data;
 }
  • もっと簡単なやり方として、以下でも同じ効果がある
    • TaskServiceをInternalTaskServiceにキャストする
    • InternalTaskService#getTaskContent(taskId)を呼ぶ
  • WorkItemを取得して getParameter でも良い。
  • なおタスク変数を使うには、タスクノードのプロパティでタスク変数のマッピング設定を行い、以下のタグがBPMNのXML内に設定されている必要があります。
    ・ioSpecification
    ・dataInputAssociation
    ・dataOutputAssociation
  • タスク変数に独自の型(自分で作ったクラス)を指定したい場合は、プロセスのImportsの設定にそのクラスを指定すれば良いです。そのクラスは Serializable を実装している必要があります。
  • 似たやり方でWorkItemIdも取得できるが、このIDでWorkItemを取得できるわけでもないので、あまり使い道がなさそう…
     public long getWorkItemIdFromTask(TaskService taskService, TaskSummary task) {
       Task t = taskService.getTaskById(task.getId());
       TaskData td = t.getTaskData();
       long wid = td.getWorkItemId(); 
       return wid;
     }
  • タスク変数のアウトプット側変数のセットは、TaskService#complete の第3引数に Mapを作って渡してやればOKです。
  • 【重要】プロセス変数とタスク変数のInputでマップするときに、プロセス変数の IDとName を同じ値にしないとなぜか変数値がタスク変数に設定されません。もしかしてバグ?

ヒューマンタスクからWorkItemを取得するには

  • サンプルその1
    @SuppressWarnings("restriction")
    private void dispHumanTaskWorkItem(ProcessInstance processInstance, long tid){
      WorkflowProcessInstance wpi = (WorkflowProcessInstance) processInstance;
      NodeInstance ni = wpi.getNodeInstance(tid);
      if ( ni instanceof HumanTaskNodeInstance ) {
        HumanTaskNodeInstance htni = (HumanTaskNodeInstance) ni;
        WorkItem wi = htni.getWorkItem();
        System.out.println("wi=" + wi.toString());
      } else {
        System.out.println("Not Human Task error");
      }
    }
  • サンプルその2
     @SuppressWarnings("restriction")
     private void dispHumanTaskParams(ProcessInstance processInstance) {
       System.out.println("WorkItemによるparameter表示開始");
       WorkflowProcessInstance wpi = (WorkflowProcessInstance) processInstance;
       Collection<NodeInstance> ndis = wpi.getNodeInstances();
       for( NodeInstance ni : ndis) {
         if ( ni instanceof HumanTaskNodeInstance ) {
           HumanTaskNodeInstance htni = (HumanTaskNodeInstance) ni;
           WorkItem wi = htni.getWorkItem();
           Map<String,Object> prms = wi.getParameters();
               for (String key : prms.keySet()) {
                   System.out.println(key + " = " + prms.get(key));
               }              
               // 試しにこんなふうに パラメータ値をいじってもWorkItemの持っているハッシュ値が変わるだけであって、
               //  実際にタスク定義している値には反映されない模様
               WorkItemImpl wip = (WorkItemImpl)wi;
               wip.setParameter("GroupId", "admins"); // グループIDが変えられるかと思ったが、できず
               wip.setParameter("input1", "modified value"); // タスク変数の値を修正してみたが、反映されず
               
               //htni.setVariable("GroupId", "admins"); // これはKnowledgeRuntimeがnullで例外になります
         }
       }
           System.out.println("WorkItemによる表示終了");
     }

ヒューマンタスクのWorkItemHandlerの実装は?

  • org.jbpm.services.task.wih.LocalHTWorkItemHandler
    • RuntimeManagerで管理されているもの。これが本筋と見られる
  • java.org.jbpm.services.task.wih.NonManagedLocalHTWorkItemHandler
    • RuntimeManagerで管理されていないもの。互換のためにあるらしい

xmlファイルからのタスクパラメータの読み込み

  • このあたりでやっている模様
    • org.jbpm.bpmn2.xml.TaskHandler

タスクのポテンシャルオーナーを追加するサンプル

  • AssignmentServiceのソースが参考になる
  • ただし、この方法で追加してもtaskService#getTaskByIdでタスクを取得しなおすとリセットされてしまう
    package org.jbpm.services.task.internals.rule;  
      
    import java.util.List;  
      
    import org.kie.api.task.model.Group;  
    import org.kie.api.task.model.OrganizationalEntity;  
    import org.kie.api.task.model.Task;  
    import org.kie.internal.task.api.TaskModelProvider;  
    import org.kie.internal.task.api.model.InternalOrganizationalEntity;  
      
    public class AssignmentService {  
      
        public void assignTask(Task task) {  
            List<OrganizationalEntity> potentialOwners = task.getPeopleAssignments().getPotentialOwners();  
            potentialOwners.clear();  
              
            Group group = TaskModelProvider.getFactory().newGroup();  
            ((InternalOrganizationalEntity) group).setId("Crusaders");  
            potentialOwners.add(group);  
        }  
    }

タスクの担当GroupID,ActorIDを動的に変更する方法

  • プロセス定義の時点でGroupIDやActorIDに以下の書式でプロセス変数を設定できる
    #{processVar}
  • このprocessVarをプロセス変数として定義し、プログラムから入れ替えてやれば担当者や担当グループが動的に変更できます。

TaskService の実装解析メモ

  • InternalTaskService は TaskService を実装しているが、これもインターフェイス
  • このインターフェイスは addGroup や addUser というメンバーを持っている。
  • しかしこのメソッドは セッション全体に対するもので、タスクをターゲットとしたものではありません。
  • org.jbpm.runtime.manager.impl.task.SynchronizedTaskService が実装らしくメンバーとして org.jbpm.services.task.impl.command.CommandBasedTaskService を持っている
  • 実際の処理は CommandBasedTaskService でやっているが、CommandBasedTaskService はメンバにCommandService という Executor を持っており、これが実際の処理をコマンドとして実行する。
  • たとえば、 TaskService#activate メソッドの処理の実態は ActivateTaskCommand#execute である
  • これをさらに手繰っていくと TaskInstanceServiceImpl#activate に至る
  • この処理は LifeCycleManager というインターフェイスに渡され、 その実装は MVELLifeCycleManager#taskOperation らしい
  • さらに同クラスの evalCommands > commands が呼ばれる
  • 実装の階層は
     SynchronizedTaskService>InternalTaskService>TaskService  
  • 参考:TaskService#claim を呼んだ場合のスタックトレースの例
    at org.jbpm.services.task.internals.lifecycle.
       MVELLifeCycleManager.evalCommand(MVELLifeCycleManager.java:98)
    at org.jbpm.services.task.internals.lifecycle.
       MVELLifeCycleManager.taskOperation(MVELLifeCycleManager.java:322)
    at org.jbpm.services.task.identity.
       UserGroupLifeCycleManagerDecorator.taskOperation(UserGroupLifeCycleManagerDecorator.java:46)
    at org.jbpm.services.task.impl.TaskInstanceServiceImpl.claim(TaskInstanceServiceImpl.java:117)
    at org.jbpm.services.task.commands.ClaimTaskCommand.execute(ClaimTaskCommand.java:51)
    at org.jbpm.services.task.commands.ClaimTaskCommand.execute(ClaimTaskCommand.java:33)
    at org.jbpm.services.task.commands.
     TaskCommandExecutorImpl$SelfExecutionCommandService.execute(TaskCommandExecutorImpl.java:65)
    at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:41)
    at org.jbpm.services.task.persistence.TaskTransactionInterceptor.execute(TaskTransactionInterceptor.java:54)
    at org.jbpm.services.task.commands.
     TaskCommandExecutorImpl.execute(TaskCommandExecutorImpl.java:40)
    at org.jbpm.services.task.impl.command.CommandBasedTaskService.claim(CommandBasedTaskService.java:136)
    at org.jbpm.runtime.manager.impl.task.SynchronizedTaskService.claim(SynchronizedTaskService.java:100)
    at com.sample.ProcessTest.testProcess(ProcessTest.java:97)

claimについて

  • 他のユーザがclaim済み(ステータス=Reserved)のタスクを他のユーザで claimなりstart させようとするとPermissionDeniedException がスローされます
  • メッセージの例
    org.jbpm.services.task.exception.PermissionDeniedException: 
    User '[UserImpl:'mary']' does not have permissions to 
    execution operation 'Start' on task id 1
  • また、claim したユーザはそのタスクの ActualOwner に設定されます。
  • 同じユーザで2回claimするのもダメです。同様のエラーになります。

delegateとforwardの違い

  • delegateは ActualOwner から任意の他のユーザーへActualOwnerを引き継ぐ。
  • delegateで引き継ぎ先に指定されたユーザーはポテンシャルオーナーに追加され、ActualOwnerになる。
  • delegateの引き継ぎ元、引き継ぎ先にはグループは指定できない。
  • delegateの引き継ぎ先ユーザーはタスクで候補指定されたグループにいない人でもOK
  • forwardはポテンシャルオーナー(ActorId)に登録されているユーザーからフォワード先のユーザーへポテンシャルオーナーを交代する。
  • フォワード先のユーザーはActualOwnerにはならず、ポテンシャルオーナーになるだけ
  • フォワード元のユーザーはフォワードしたらポテンシャルオーナーから消える
  • フォワード元のユーザーはプロセスのGroupIdに指定されたグループに所属しているだけではダメ。ActorIdに個人として登録されている必要がある。(ポテンシャルオーナーとして入れ替わる場所がないとダメ)
  • フォワード先にグループも指定できる。ただしこのグループはフォワード元のユーザーが属しているグループでなくてはダメ
  • フォワード先にユーザーを指定する場合は、フォワード元のユーザーが属しているグループに属していなくても良い。(グループは属してないとダメなのに…不可解な仕様です)
  • フォワード元にグループは指定できない。
  • つまり、delegateとforwardを組み合わせることによって、候補のユーザーやグループを動的に追加していくことが可能となる。(ただし、プロセス定義が書き換わるわけではなく、そのプロセスインスタンスのみの変更です)

stop/releaseについて

  • stopは、startしてInProgressになっているタスクをReservedなステータスへ戻す。
  • ちなみに、ReservedからReadyに戻すにはreleaseする。(forwardでもそうなるが、その場合はポテンシャルオーナーも変わる)

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2014-10-08 (水) 22:47:35 (2387d)