Shark 工作流研究2-用户角色映射

当用JaWE创建流程时候,会将相关活动放到对应的角色中。而当启动流程时候需要将角色映射到具体的用户上面,才能将具体任务分配给具体用户。 Shark 可以将一个角色映射到一个单独的用户,也可以将角色映射到一个用户组。如果映射到单独的用户,则该角色的任务只会出现在该用户的任务列表里;如果映射到一组用户,则该角色的任务会出现在这个组的所有用户的任务列表里,如果其中一个用户接收了这个任务,则该任务会在该组其他成员的任务列表里删除。

但是根据代码分析,Shark将一个流程或一个包的角色映射存在数据库中,每当启动一个流程时候,Shark会到数据库中查找此流程的角色映射信息,如果找到就把相应的任务分配给相关用户;如果没有找到映射信息,则把所有任务都分配给启动流程的那个用户。这样就会出现一个问题,不便于在启动流程时候动态的映射角色和用户,因为角色和固定用户的映射信息是静态的存储在数据库中的,目前的方法只能每次启动之前重新映射角色,这样每次都会有数据库更改操作,增加了数据库读取操作,对性能造成影响,如果有大量并发时候,很有可能由于更改数据库造成问题。所以此处需要改进,合理的办法是允许将角色映射信息传入到流程启动参数中去,这样派发流程的人员就可以根据实际情况选择不同的处理人,即使派发的是同一个流程。

下面看一下映射角色的代码。由于JspClient示例中没有相关映射角色的操作,所以使用的是Shark Admin这个Swing客户端管理程序,此程序可以使用在Shark安装目录下的bin目录下的runSA.bat文件启动。具体使用方法可以参考安装目录下的doc/QuickStartExample/index.html文件。该程序有一个"User management"标签下有一个"Mapping"功能,就是进行角色映射的功能。其源代码为 org.enhydra.shark.swingclient.workflowadmin.user.UserMapping类。下面这个方法即是保存映射信息的操作:

protected void applyChanges() {
    if (participants.isSelectionEmpty() || usernames.isSelectionEmpty())
        return;
    UserTransaction ut = null;
    try {
        ut = SharkInterfaceWrapper.getUserTransaction();
        ut.begin();
        ParticipantMap pm = SharkInterfaceWrapper.getParticipantMappingsAdmin().createParticipantMap();
        pm.setPackageId(pkgId.getText());
        pm.setProcessDefinitionId(procDefId.getText());
        pm.setParticipantId(participantId.getText());
        pm.setUsername(username.getText());
        if (ResourceManager.getLanguageDependentString("IsGroupUserTRUEKey").equalsIgnoreCase(
            isGroupUser.getText().trim()))
            pm.setIsGroupUser(true);
        else
            pm.setIsGroupUser(false);
        SharkInterfaceWrapper.getParticipantMappingsAdmin().saveParticipantMapping(pm);
        umm.refresh(true);
        ut.commit();
    } catch (Exception ex) {
        try {
            ut.rollback();
        } catch (Exception _) {
        }
        JOptionPane.showMessageDialog(umm.getWindow(),
            ResourceManager.getLanguageDependentString("MessageMappingAlreadyExistsOrCannotBeAddedAtTheMoment"),
            ResourceManager.getLanguageDependentString("WorkflowAdminTitle"), JOptionPane.INFORMATION_MESSAGE);
    }
}

构造一个ParticipantMap,将映射信息放入ParticipantMap中,然后保存到数据库中。 SharkInterfaceWrapper.getParticipantMappingsAdmin().saveParticipantMapping(pm); 根据反射机制实际上是调用的类 org.enhydra.shark.partmappersistence.DODSParticipantMappingAdmin的 saveParticipantMapping(pm)方法:

/**
 * Save new ParticipantMap to database.
 *
 * @param pm ParticipantMap to save
 * @return boolean true if everything is ok, false otherwise
 * @exception Exception Exception will be thrown if error occur.
 */
public boolean saveParticipantMapping(ParticipantMap pm) throws Exception {
    boolean retVal = true;
    if (!checkValidity(pm)) {
        throw new Exception("Participant mapping [ " + pm + " ] is not valid");
    }
    if (doesParticipantMappingExist(pm)) {
        throw new Exception("Participant mapping already exists");
    }
    DBTransaction dbt = getDBTransaction();
    // if group user
    if (pm.getIsGroupUser()) {
        // FIXME
        // GroupUserProcLevelParticipantDO mappDO =
        // GroupUserProcLevelParticipantDO.createVirgin();
        GroupUserDO groupDO = this.checkGroups(pm);
        // process level participant
        if (pm.getProcessDefinitionId() != null) {
            ProcLevelParticipantDO procLevPartDO = this.checkProcLevelParticipant(pm);
            GroupUserProcLevelParticipantDO gplPart = GroupUserProcLevelParticipantDO.createVirgin(dbt);
            gplPart.setPARTICIPANTOID(procLevPartDO);
            gplPart.setUSEROID(groupDO);
            gplPart.save();
        }
        // package level participant
        else {
            PackLevelParticipantDO pckgLevPartDO = this.checkPackLevelParticipant(pm);
            GroupUserPackLevelParticipantDO gplPart = GroupUserPackLevelParticipantDO.createVirgin(dbt);
            gplPart.setPARTICIPANTOID(pckgLevPartDO);
            gplPart.setUSEROID(groupDO);
            gplPart.save();
        }
    }
    // if single user
    else {
        // FIXME
        // UserProcLevelParticipantDO mappDO =
        // UserProcLevelParticipantDO.createVirgin(dbt);
        NormalUserDO userDO = this.checkUsers(pm);
        if (pm.getProcessDefinitionId() != null) {
            ProcLevelParticipantDO procLevPartDO = this.checkProcLevelParticipant(pm);
            UserProcLevelParticipantDO uplPart = UserProcLevelParticipantDO.createVirgin(dbt);
            uplPart.setPARTICIPANTOID(procLevPartDO);
            uplPart.setUSEROID(userDO);
            uplPart.save();
        } else {
            PackLevelParticipantDO pckgLevPartDO = this.checkPackLevelParticipant(pm);
            UserPackLevelParticipantDO uplPart = UserPackLevelParticipantDO.createVirgin(dbt);
            uplPart.setPARTICIPANTOID(pckgLevPartDO);
            uplPart.setUSEROID(userDO);
            uplPart.save();
        }
    }
    return retVal;
}

根据映射单个用户还是映射组用户分别处理,根据映射单个流程还是映射整个包分别把映射信息存储到SHKProcLevelParticipant表 (ProcLevelParticipantDO类为该表的实体类)和SHKPackLevelParticipant表 (PackLevelParticipantDO类为该表的实体类)。 DODSParticipantMappingAdmin类有一个getParticipantMappings(WMSessionHandle shandle, String packageId, String packageVer,String processDefinitionId, String participantId)查找映射信息,根据代码分析,其调用情况如下(省略了参数):

WfActivityImpl.startActivity()->WfActivityImpl.runNo()->WfActivityImpl.createAssignments()-> WfActivityImpl.findUsers()->StandardAssignmentManager.getAssignments()-> StandardAssignmentManager.findResources()->DODSParticipantMappingAdmin.getParticipantMappings()

当启动流程后,会启动流程的活动,这个时候该活动就根据角色映射信息把任务分配给相应的具体用户。目前已经清楚了Shark的角色映射机制,如果实际应用中每类流程的处理人员变动比较小的话,可以使用启动流程前重新映射的方式;如果变动比较频繁的话,为了效率和安全性,则需要添加动态映射的机制。目前想到的方法是可以根据具体的流程实例保存映射信息,即每个流程都有相应的映射信息保存,而不是所有同类流程使用同一个映射信息,这样就可以使同一流程的不同实例拥有不同的处理人了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值