Issue: business key in a call activiti

https://community.alfresco.com/thread/221280-business-key-in-a-call-activity

这个帖子有一些讨论和回复。

 

https://community.alfresco.com/thread/218788-call-activity-and-businesskey#

这个帖子一直没人回答。

 

https://stackoverflow.com/questions/26497569/activity-how-to-know-if-an-execution-is-linked-to-an-instance-of-subprocess

 

https://community.alfresco.com/thread/221348-get-all-active-tasks-including-sub-process-tasks

这篇文章比较中肯,社区分享了两种(潜在的)WorkAround的方案,详见下边解决方案部分。

 

http://blog.csdn.net/lovemenghaibin/article/details/50608300

这个帖子是讲business key的用户的入门文章,和本问题无关。

 

act_ru_execution表的BUSINESS_KEY_ 字段,在使用call activiti时,子流程的BUSINESS_KEY_会丢失,而不能从父流程继承过来。

 

解决方案:

1.《Activiti权威指南》作者冀正,给的建议的解决办法:修改源代码,一行代码就能把丢失的BUSINESS_KEY_拷贝过来。

2.用ExecutionListener或者ActivitiEventListener监听CallActiviti的创建过程,然后把父流程实例的Business存入流程变量中。

社区网友由ExecutionListener到ActivitiEventListener逐步讨论。

a) ExecutionListener

/**
 * BusinessKeyInjectionListener.java
 * com.yuanchuangyun.workflow.listener
 *
 * Function: TODO 
 *
 *   ver     date              author
 * ──────────────────────────────────
 *            2017年12月1日         renguoqiang
 *
 * Copyright (c) 2017, yuanchuangyun All Rights Reserved.
*/

package com.yuanchuangyun.workflow.listener;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;


/**
 * ClassName:BusinessKeyInjectionExecutionListener
 * @author   renguoqiang
 * @version  
 * @since    Ver 1.1
 * @Date     2017年12月1日        下午4:10:37
 *
 * @see      
 */
public class BusinessKeyInjectionExecutionListener implements ExecutionListener{

    /**
     * serialVersionUID:TODO(用一句话描述这个变量表示什么)
     *
     * @since Ver 1.1
     */
    
    private static final long serialVersionUID = 1L;

    @Override
    public void notify(DelegateExecution exec) throws Exception {
      System.out.println("In BusinessKey Injection Listener");

      ExecutionEntity thisEntity = (ExecutionEntity)exec;
      ExecutionEntity superExecEntity = thisEntity.getSuperExecution();

      String key = "";

      // Check if this is the main process.
      if( superExecEntity == null ){
          // If it is, get the business key the main process was launched with.
          key = thisEntity.getBusinessKey();
      }else{
        // We are a subprocess so get the BusinessKey variable set by the caller.
        // This should work for N level deep sub processes.
        key = (String)superExecEntity.getVariable("BusinessKey");
      }

      // Set a process variable with the business key. Can't actually set business key because business keys
      // have to be unique per process instance.
      thisEntity.setVariable("BusinessKey", key);
    }

}

 

b) ActivitiEventListener

/**
 * BusinessKeyInjectionActivitiEventListener.java
 * com.yuanchuangyun.workflow.listener
 *
 * Function: TODO 
 *
 *   ver     date              author
 * ──────────────────────────────────
 *            2017年12月1日         renguoqiang
 *
 * Copyright (c) 2017, yuanchuangyun All Rights Reserved.
 */

package com.yuanchuangyun.workflow.listener;

import org.activiti.engine.delegate.event.ActivitiEntityEvent;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;

/**
 * ClassName:BusinessKeyInjectionActivitiEventListener
 * @author renguoqiang
 * @version
 * @since Ver 1.1
 * @Date 2017年12月1日 下午5:03:29
 *
 * @see
 */
public class BusinessKeyInjectionActivitiEventListener implements ActivitiEventListener {
    private String getSuperProcessInstanceId(ExecutionEntity exEntity) {
        if (exEntity != null && exEntity.getSuperExecution() != null) {
            return getSuperProcessInstanceId(exEntity.getSuperExecution());
        } else if (exEntity != null) {
            return exEntity.getProcessInstanceId();
        }

        return null;
    }

    @Override
    public void onEvent(ActivitiEvent event) {
        switch (event.getType()) {
            case TASK_CREATED:
                if (event instanceof ActivitiEntityEvent) {
                    ActivitiEntityEvent activityEntityEvent = (ActivitiEntityEvent) event;
    
                    TaskEntity taskEntity = (TaskEntity) activityEntityEvent
                            .getEntity();
                    ExecutionEntity exEntity = taskEntity.getExecution();
                    String superExId = getSuperProcessInstanceId(exEntity != null ? exEntity
                            .getSuperExecution() : null);
    
                    if (superExId != null) {
                        taskEntity.setAssignee(superExId);
                    }
    
                    try {
                        @SuppressWarnings("null")
                        ExecutionEntity executionEntity = (ExecutionEntity) activityEntityEvent
                                .getEntity();
    
                        ExecutionEntity superExecEntity = executionEntity
                                .getSuperExecution();
                        String key = "";
    
                        // Check if this is the main process.
                        if (superExecEntity == null) {
                            // key = executionEntity.getBusinessKey();
                            key = (String) executionEntity
                                    .getVariable("BusinessKey");
                        } else {
                            key = (String) superExecEntity
                                    .getVariable("BusinessKey");
                        }
    
                        executionEntity.setVariable("BusinessKey", key);
    
                    } catch (Exception e) {
                        // System.out.println("ENTITY CAST ERROR !!!!!!!!");
                    }

                    break;
                    // ...
                }
            default:
                break;
        }
    }

    @Override
    public boolean isFailOnException() {
        // TODO Auto-generated method stub
        return false;
    }
}

 

TIP:从Activiti的官方文档,可知BusinessKey这个列,预留只是为了兼容一些历史问题。系统设计时,应该避免使用此值,这样Activiti就更独立一下(耦合小),也就是把业务的主键与ProcessInstanceId的关联记录,放入自定义的业务表中存储。

 

源码附件:https://files.cnblogs.com/files/rgqancy/BusinessKey.zip

posted @ 2017-07-17 16:08  任国强  阅读(1016)  评论(0编辑  收藏  举报