需求:有时候有的任务需要动态分配人,例如在第二个任务中的审批人是在第一个人在审批第一个任务的时候所选择的人,这个在jbpm4中可以通过第二个任务加事件来实现,但5好像行不通,就看到这个Claim函数,从单词意思上来看,正是我想要的。
认领任务
开始的设想:直接调用 claim方法,但这个方法有好几个,详细查看接口
AsyncTaskService,我想的是把第二个审批任务
的审批人设置成组用户,然后再调用claim方法
void claim( long taskId, String userId, TaskOperationResponseHandler responseHandler);
这个方法的参数刚好就是一个taskId和userId,正好。另外还有两个是需要
groupIds的,而且还加了
@Deprecated
,所以就没有考虑,可当我调用了这个后却出异常,说我没权限操作,我这个用户也是在这个组里面的,然后就开始了看它的代码。
List<Object> args = new ArrayList<Object>( 3 );
args.add( Operation. Claim );
args.add( taskId );
args.add( userId );
Command cmd = new Command ( counter .getAndIncrement(),
CommandName. OperationRequest,
args );
handler. addResponseHandler( cmd.getId(),
responseHandler );
connector.write( cmd );
并通过消息传送到TaskServerHandler中
2.在TaskServerHandler中解析参数并跳转到TaskServiceSession中
3.在TaskServiceSession中执行命令
void evalCommand( final Operation operation, final List<OperationCommand> commands, final Task task,
final User user, final OrganizationalEntity targetEntity,
List<String> groupIds) throws PermissionDeniedException {
final TaskData taskData = task.getTaskData();
boolean statusMatched = false ;
for ( OperationCommand command : commands) {
// first find out if we have a matching status
if (command.getStatus() != null ) {
for (Status status : command.getStatus()) {
if (taskData.getStatus() == status) {
statusMatched = true ;
// next find out if the user can execute this doOperation
if (!isAllowed(command, task, user, groupIds)) {
String errorMessage = "User '" + user + "' does not have permissions to execution operation '" + operation + "' on task id " + task.getId();
throw new PermissionDeniedException(errorMessage);
}
commands(command, task, user, targetEntity);
}
else {
logger .debug( "No match on status for task " + task.getId() + ": status " + taskData.getStatus() + " != " + status);
}
}
}
if (command.getPreviousStatus() != null ) {
for (Status status : command.getPreviousStatus()) {
if (taskData.getPreviousStatus() == status) {
statusMatched = true ;
// next find out if the user can execute this doOperation
if (!isAllowed(command, task, user, groupIds)) {
String errorMessage = "User '" + user + "' does not have permissions to execution operation '" + operation + "' on task id " + task.getId();
throw new PermissionDeniedException(errorMessage);
}
commands(command, task, user, targetEntity);
}
else {
logger .debug( "No match on previous status for task " + task.getId() + ": status " + taskData.getStatus() + " != " + status);
}
}
}
}
if (!statusMatched) {
String errorMessage = "User '" + user + "' was unable to execution operation '" + operation + "' on task id " + task.getId() + " due to a no 'current status' match" ;
throw new PermissionDeniedException(errorMessage);
}
}
3.这里面有个关键就是
if
(!isAllowed(command, task, user, groupIds)) { 会判断当前是否可以执行
private boolean isAllowed ( final OperationCommand command, final Task task, final User user,
List<String> groupIds) {
final PeopleAssignments people = task.getPeopleAssignments();
final TaskData taskData = task.getTaskData();
boolean operationAllowed = false ;
for (Allowed allowed : command.getAllowed()) {
if (operationAllowed) {
break ;
}
switch (allowed) {
case Owner : {
operationAllowed = (taskData.getActualOwner() != null && taskData.getActualOwner().equals(user));
break ;
}
case Initiator : {
operationAllowed = (taskData.getCreatedBy() != null &&
(taskData.getCreatedBy().equals(user))
|| (groupIds != null && groupIds.contains(taskData.getCreatedBy().getId())));
break ;
}
case PotentialOwner : {
operationAllowed = isAllowed(user, groupIds, people.getPotentialOwners());
break ;
}
case BusinessAdministrator : {
operationAllowed = isAllowed(user, groupIds, people.getBusinessAdministrators());
break ;
}
case Anyone : {
operationAllowed = true ;
break ;
}
}
}
if (operationAllowed && command.isUserIsExplicitPotentialOwner()) {
// if user has rights to execute the command, make sure user is explicitly specified (not as a group)
operationAllowed = people.getPotentialOwners().contains(user);
}
if (operationAllowed && command.isSkippable()) {
operationAllowed = taskData.isSkipable();
}
return operationAllowed;
}
4.从这个函数可以看出除了
Anyone其他的都是要经过一系列判断,而这个allowed又是在和TaskServiceSession同目录中的
operations-dsl.mvel 中已经配置好了的
[ Operation.Claim
: [ new OperationCommand().{
status = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner, Allowed.BusinessAdministrator ],
setNewOwnerToUser = true,
newStatus = Status.Reserved
} ],
Operation.Start
: [ new OperationCommand().{
status = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner ],
setNewOwnerToUser = true,
newStatus = Status.InProgress
},
new OperationCommand().{
status = [ Status.Reserved ],
allowed = [ Allowed.Owner ],
newStatus = Status.InProgress
} ],
Operation.Stop
: [ new OperationCommand().{
status = [ Status.InProgress ],
allowed = [ Allowed.Owner, Allowed.BusinessAdministrator ],
newStatus = Status.Reserved
} ],
Operation.Release
: [ new OperationCommand().{
status = [ Status.Reserved, Status.InProgress ],
allowed = [Allowed.Owner, Allowed.BusinessAdministrator ],
setNewOwnerToNull = true,
newStatus = Status.Ready
} ],
Operation.Suspend
: [ new OperationCommand().{
status = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner, Allowed.BusinessAdministrator ],
newStatus = Status.Suspended
},
new OperationCommand().{
status = [ Status.Reserved, Status.InProgress ],
allowed = [Allowed.Owner, Allowed.BusinessAdministrator ],
newStatus = Status.Suspended
} ],
Operation.Resume
: [ new OperationCommand().{
previousStatus = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner, Allowed.BusinessAdministrator ],
setToPreviousStatus = true
},
new OperationCommand().{
previousStatus = [ Status.Reserved, Status.InProgress ],
allowed = [ Allowed.Owner, Allowed.BusinessAdministrator ],
setToPreviousStatus = true
} ],
Operation.Skip
: [ new OperationCommand().{
status = [ Status.Created ],
allowed = [ Allowed.Initiator, Allowed.BusinessAdministrator ],
newStatus = Status.Obsolete,
skippable = true
},
new OperationCommand().{
status = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner, Allowed.BusinessAdministrator ],
newStatus = Status.Obsolete,
skippable = true
},
new OperationCommand().{
status = [ Status.Reserved, Status.InProgress ],
allowed = [ Allowed.Owner, Allowed.BusinessAdministrator ],
newStatus = Status.Obsolete,
skippable = true
} ],
Operation.Delegate
: [ new OperationCommand().{
status = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner, Allowed.BusinessAdministrator ],
addTargetUserToPotentialOwners = true,
newStatus = Status.Ready,
exec = Operation.Claim
},
new OperationCommand().{
status = [ Status.Reserved, Status.InProgress ],
allowed = [ Allowed.Owner, Allowed.BusinessAdministrator ],
addTargetUserToPotentialOwners = true,
newStatus = Status.Ready,
exec = Operation.Claim
} ],
Operation.Forward
: [ new OperationCommand().{
status = [ Status.Ready ],
allowed = [ Allowed.PotentialOwner, Allowed.BusinessAdministrator ],
userIsExplicitPotentialOwner = true,
addTargetUserToPotentialOwners = true,
removeUserFromPotentialOwners = true,
setNewOwnerToNull = true,
newStatus = Status.Ready
},
new OperationCommand().{
status = [ Status.Reserved, Status.InProgress ],
allowed = [ Allowed.Owner, Allowed.BusinessAdministrator ],
userIsExplicitPotentialOwner = true,
addTargetUserToPotentialOwners = true,
removeUserFromPotentialOwners = true,
setNewOwnerToNull = true,
newStatus = Status.Ready
}],
Operation.Complete
: [ new OperationCommand().{
status = [ Status.InProgress ],
allowed = [ Allowed.Owner ],
newStatus = Status.Completed
} ],
Operation.Fail
: [ new OperationCommand().{
status = [ Status.InProgress ],
allowed = [ Allowed.Owner ],
newStatus = Status.Failed
} ],
Operation.Register
: [ new OperationCommand().{
status = [ Status.Created, Status.Ready, Status.Reserved, Status.InProgress, Status.Suspended ],
allowed = [ Allowed.Anyone ]
} ],
Operation.Remove
: [ new OperationCommand().{
status = [ Status.Created, Status.Ready, Status.Reserved, Status.InProgress, Status.Suspended ],
allowed = [ Allowed.Anyone ]
} ],
Operation.Activate
: [ new OperationCommand().{
status = [ Status.Created ],
allowed = [ Allowed.Owner, Allowed.BusinessAdministrator ],
newStatus = Status.Ready
} ],
Operation.Exit
: [ new OperationCommand().{
status = [ Status.Created, Status.Ready, Status.Reserved, Status.InProgress, Status.Suspended ],
allowed = [ Allowed.BusinessAdministrator ],
newStatus = Status.Exited
} ]
]
可以看出
Operation.Claim对应的allowed是
Allowed.PotentialOwner, Allowed.BusinessAdministrator,回到刚才的判断中可以看出这两种对应的判断都需要
groupIds。
可以再看下isAllowed的实现
private boolean isAllowed ( final User user, final List<String> groupIds, final List<OrganizationalEntity> entities) {
// for now just do a contains, I'll figure out group membership later.
for (OrganizationalEntity entity : entities) {
if (entity instanceof User && entity.equals(user)) {
return true ;
}
if (entity instanceof Group && groupIds != null && groupIds.contains(entity.getId())) {
return true ;
}
}
return false ;
}
第一个if里面应该就是这个任务已经指定了人,刚好就是他
第二个if里面就是判断这个组是否包含这个任务指定的组id
可以看出这个isAllowed主要还是根据这个任务的审批人类型来进行判断的,
到这里就可以看出来我开始的设想出错了,必须得带上这个组,个人感觉有点多余
解决办法:
1.调用
void claim ( long taskId, String userId, List<String> groupIds, TaskOperationResponseHandler responseHandler);
加上groupIds,比较麻烦,业务系统在调用的时候还得先知道这个组
2.
修改
operations-dsl.mvel
,把Claim的Allowed修改为
Allowed.Anyone
3.自己在业务系统与jbpm5中间加一层,去查询出
groupIds,查询表
organizationalentity