→jBPM Suite関連Tips

#contents

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

*関連Web [#bb4fd608]
-[[How to add users/groups to Human Task Service in BRMS / BPM Suite>https://access.redhat.com/solutions/155533]]

-[[How to implement a custom UserGroupCallback in BPM Suite 6>https://access.redhat.com/solutions/1149763]]

-[[How to implement Task Event Listeners in BPM Suite 6.0 ?>https://access.redhat.com/solutions/883683]]


*タスクからタスク変数を参照する [#j66e5531]
  //このやり方で一応取得できるようですが、もっと簡単な方法がないのだろうか…
  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を取得するには [#p0904e27]
-サンプルその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の実装は? [#t0746159]
-org.jbpm.services.task.wih.LocalHTWorkItemHandler
--RuntimeManagerで管理されているもの。これが本筋と見られる	
-java.org.jbpm.services.task.wih.NonManagedLocalHTWorkItemHandler
--RuntimeManagerで管理されていないもの。互換のためにあるらしい	


*xmlファイルからのタスクパラメータの読み込み [#k444d18b]
-このあたりでやっている模様
--org.jbpm.bpmn2.xml.TaskHandler


*タスクのポテンシャルオーナーを追加するサンプル [#labf85ab]
-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を動的に変更する方法 [#z049e0d8]
-プロセス定義の時点でGroupIDやActorIDに以下の書式でプロセス変数を設定できる
 #{processVar}
-このprocessVarをプロセス変数として定義し、プログラムから入れ替えてやれば担当者や担当グループが動的に変更できます。


*TaskService の実装解析メモ [#q61e7475]
-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について [#cb90c077]
-他のユーザが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の違い [#va1e6d27]
-delegateは ActualOwner から任意の他のユーザーへActualOwnerを引き継ぐ。
-delegateで引き継ぎ先に指定されたユーザーはポテンシャルオーナーに追加され、ActualOwnerになる。
-delegateの引き継ぎ元、引き継ぎ先にはグループは指定できない。
-delegateの引き継ぎ先ユーザーはタスクで候補指定されたグループにいない人でもOK

-forwardはポテンシャルオーナー(ActorId)に登録されているユーザーからフォワード先のユーザーへポテンシャルオーナーを交代する。
-フォワード先のユーザーはActualOwnerにはならず、ポテンシャルオーナーになるだけ
-フォワード元のユーザーはフォワードしたらポテンシャルオーナーから消える
-フォワード元のユーザーはプロセスのGroupIdに指定されたグループに所属しているだけではダメ。ActorIdに個人として登録されている必要がある。(ポテンシャルオーナーとして入れ替わる場所がないとダメ)
-フォワード先にグループも指定できる。ただしこのグループはフォワード元のユーザーが属しているグループでなくてはダメ
-フォワード先にユーザーを指定する場合は、フォワード元のユーザーが属しているグループに属していなくても良い。(グループは属してないとダメなのに…不可解な仕様です)
-フォワード元にグループは指定できない。

-つまり、delegateとforwardを組み合わせることによって、候補のユーザーやグループを動的に追加していくことが可能となる。(ただし、プロセス定義が書き換わるわけではなく、そのプロセスインスタンスのみの変更です)


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

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS