1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.impl.peopleflow;
17
18 import org.apache.commons.collections.CollectionUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.CoreConstants;
21 import org.kuali.rice.core.api.config.ConfigurationException;
22 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
23 import org.kuali.rice.core.api.exception.RiceIllegalStateException;
24 import org.kuali.rice.core.api.membership.MemberType;
25 import org.kuali.rice.core.api.util.VersionHelper;
26 import org.kuali.rice.kew.actionrequest.ActionRequestFactory;
27 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
28 import org.kuali.rice.kew.actionrequest.KimGroupRecipient;
29 import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
30 import org.kuali.rice.kew.actionrequest.Recipient;
31 import org.kuali.rice.kew.api.action.ActionRequestPolicy;
32 import org.kuali.rice.kew.api.action.ActionRequestType;
33 import org.kuali.rice.kew.api.action.RecipientType;
34 import org.kuali.rice.kew.api.document.Document;
35 import org.kuali.rice.kew.api.document.DocumentContent;
36 import org.kuali.rice.kew.api.peopleflow.PeopleFlowDefinition;
37 import org.kuali.rice.kew.api.peopleflow.PeopleFlowDelegate;
38 import org.kuali.rice.kew.api.peopleflow.PeopleFlowMember;
39 import org.kuali.rice.kew.api.repository.type.KewTypeDefinition;
40 import org.kuali.rice.kew.api.repository.type.KewTypeRepositoryService;
41 import org.kuali.rice.kew.engine.RouteContext;
42 import org.kuali.rice.kew.framework.peopleflow.PeopleFlowTypeService;
43 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
44 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValueContent;
45 import org.kuali.rice.kim.api.group.Group;
46 import org.kuali.rice.kim.api.identity.principal.Principal;
47 import org.kuali.rice.kim.api.role.Role;
48 import org.kuali.rice.kim.api.role.RoleMembership;
49 import org.kuali.rice.kim.api.role.RoleService;
50 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
51 import org.kuali.rice.ksb.api.KsbApiServiceLocator;
52 import org.kuali.rice.ksb.api.bus.Endpoint;
53
54 import javax.xml.namespace.QName;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.List;
58 import java.util.Map;
59
60
61
62
63
64
65
66 public class PeopleFlowRequestGeneratorImpl implements PeopleFlowRequestGenerator {
67
68 private KewTypeRepositoryService typeRepositoryService;
69 private RoleService roleService;
70
71 @Override
72 public List<ActionRequestValue> generateRequests(RouteContext routeContext, PeopleFlowDefinition peopleFlow, ActionRequestType actionRequested) {
73 Context context = new Context(routeContext, peopleFlow, actionRequested);
74 for (PeopleFlowMember member : peopleFlow.getMembers()) {
75 generateRequestForMember(context, member);
76 }
77
78 return context.getActionRequestFactory().getRequestGraphs();
79 }
80
81 protected void generateRequestForMember(Context context, PeopleFlowMember member) {
82
83 List<ActionRequestValue> memberRequests = new ArrayList<ActionRequestValue>();
84
85 if (MemberType.ROLE == member.getMemberType()) {
86 memberRequests.addAll(findNonRoleRequests(generateRequestsForRoleMember(context, member)));
87 } else {
88 ActionRequestValue actionRequest = context.getActionRequestFactory().addRootActionRequest(
89 context.getActionRequested().getCode(), member.getPriority(), toRecipient(member), "",
90 member.getResponsibilityId(), Boolean.TRUE, getActionRequestPolicyCode(member), null);
91
92 if (actionRequest != null) {
93 memberRequests.add(actionRequest);
94 }
95 }
96
97
98 generateDelegationRequests(context, memberRequests, member);
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112 protected List<ActionRequestValue> generateRequestsForRoleMember(Context context, PeopleFlowMember member) {
113 List<ActionRequestValue> roleMemberRequests = new ArrayList<ActionRequestValue>();
114
115 List<Map<String, String>> roleQualifierMaps = loadRoleQualifiers(context, member.getMemberId());
116 Role role = getRoleService().getRole(member.getMemberId());
117
118 boolean hasPeopleFlowDelegates = !CollectionUtils.isEmpty(member.getDelegates());
119
120 if (role == null) {
121 throw new IllegalStateException("Failed to locate a role with the given role id of '" +
122 member.getMemberId() + "'");
123 }
124
125 if (CollectionUtils.isEmpty(roleQualifierMaps)) {
126 ActionRequestValue request = addKimRoleRequest(context, member, role, Collections.<String, String>emptyMap(),
127 hasPeopleFlowDelegates);
128
129 if (request != null) {
130 roleMemberRequests.add(request);
131 }
132 } else {
133
134 for (Map<String, String> roleQualifiers : roleQualifierMaps) {
135 ActionRequestValue request = addKimRoleRequest(context, member, role, roleQualifiers,
136 hasPeopleFlowDelegates);
137 if (request != null) {
138 roleMemberRequests.add(request);
139 }
140 }
141 }
142
143 return roleMemberRequests;
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158 private ActionRequestValue addKimRoleRequest(Context context, PeopleFlowMember member, Role role,
159 Map<String, String> roleQualifiers, boolean ignoreKimDelegates) {
160
161 ActionRequestValue roleMemberRequest = null;
162
163 List<RoleMembership> memberships = getRoleService().getRoleMembers(Collections.singletonList(
164 member.getMemberId()), roleQualifiers);
165
166 String actionRequestPolicyCode = getActionRequestPolicyCode(member);
167
168 if (!CollectionUtils.isEmpty(memberships)) {
169 roleMemberRequest = context.getActionRequestFactory().addKimRoleRequest(
170 context.getActionRequested().getCode(), member.getPriority(), role, memberships, null,
171 member.getResponsibilityId(), true, actionRequestPolicyCode, null, ignoreKimDelegates);
172
173 }
174
175 return roleMemberRequest;
176 }
177
178
179
180
181
182
183
184
185
186
187 private void generateDelegationRequests(Context context, List<ActionRequestValue> memberRequests,
188 PeopleFlowMember member) {
189
190 if (CollectionUtils.isEmpty(member.getDelegates()) || CollectionUtils.isEmpty(memberRequests)) {
191 return;
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205 for (PeopleFlowDelegate delegate : member.getDelegates()) {
206 for (ActionRequestValue memberRequest : memberRequests) {
207 if (MemberType.ROLE == delegate.getMemberType()) {
208 generateDelegationToRoleRequests(context, memberRequest, member, delegate);
209 } else {
210 generateDelegationToNonRoleRequest(context, memberRequest, member, delegate);
211 }
212 }
213 }
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227 private void generateDelegationToNonRoleRequest(Context context, ActionRequestValue memberRequest,
228 PeopleFlowMember member, PeopleFlowDelegate delegate) {
229
230 Recipient recipient;
231
232 if (MemberType.PRINCIPAL == delegate.getMemberType()) {
233 recipient = new KimPrincipalRecipient(delegate.getMemberId());
234 } else if (MemberType.GROUP == delegate.getMemberType()) {
235 recipient = new KimGroupRecipient(delegate.getMemberId());
236 } else {
237 throw new RiceIllegalStateException("MemberType unknown: " + delegate.getMemberType());
238 }
239
240 String actionRequestPolicyCode = getDelegateActionRequestPolicyCode(member, delegate);
241
242 String delegationAnnotation = generateDelegationAnnotation(memberRequest, member, delegate);
243
244 context.getActionRequestFactory().addDelegationRequest(memberRequest, recipient,
245 delegate.getResponsibilityId(), memberRequest.getForceAction(),
246 delegate.getDelegationType(), actionRequestPolicyCode, delegationAnnotation, null);
247 }
248
249
250
251
252
253
254
255
256
257 private String generateDelegationAnnotation(ActionRequestValue parentRequest, PeopleFlowMember member,
258 PeopleFlowDelegate delegate) {
259
260 StringBuffer annotation = new StringBuffer( "Delegation of: " );
261 annotation.append( parentRequest.getAnnotation() );
262 annotation.append( " to " );
263
264 if (delegate.getMemberType() == MemberType.PRINCIPAL) {
265 annotation.append( "principal " );
266 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(delegate.getMemberId());
267
268 if ( principal != null ) {
269 annotation.append( principal.getPrincipalName() );
270 } else {
271 annotation.append( member.getMemberId() );
272 }
273 } else if (delegate.getMemberType() == MemberType.GROUP) {
274 annotation.append( "group " );
275 Group group = KimApiServiceLocator.getGroupService().getGroup(delegate.getMemberId());
276
277 if ( group != null ) {
278 annotation.append( group.getNamespaceCode() ).append( '/' ).append( group.getName() );
279 } else {
280 annotation.append( member.getMemberId() );
281 }
282 } else {
283 annotation.append( "?????? '" );
284 annotation.append( member.getMemberId() );
285 annotation.append( "'" );
286 }
287
288 return annotation.toString();
289 }
290
291
292
293
294
295
296
297
298
299
300
301
302 protected void generateDelegationToRoleRequests(Context context,
303 ActionRequestValue parentRequest, PeopleFlowMember member, PeopleFlowDelegate delegate) {
304
305 List<Map<String, String>> roleQualifierList = loadRoleQualifiers(context, delegate.getMemberId());
306 Role role = getRoleService().getRole(delegate.getMemberId());
307
308 if (role == null) {
309 throw new IllegalStateException("Failed to locate a role with the given role id of '" +
310 delegate.getMemberId() + "'");
311 }
312
313 if (CollectionUtils.isEmpty(roleQualifierList)) {
314 addKimRoleDelegateRequest(context, parentRequest, member, delegate, role,
315 Collections.<String, String>emptyMap());
316 } else {
317 for (Map<String, String> roleQualifiers : roleQualifierList) {
318 List<RoleMembership> memberships = getRoleService().getRoleMembers(Collections.singletonList(
319 member.getMemberId()), roleQualifiers);
320 for (RoleMembership membership : memberships) {
321 if (membership.getType().equals(MemberType.PRINCIPAL)
322 && StringUtils.equals(membership.getMemberId(), parentRequest.getPrincipalId())) {
323 addKimRoleDelegateRequest(context, parentRequest, member, delegate, role, roleQualifiers);
324 } else if (membership.getType().equals(MemberType.GROUP)
325 && StringUtils.equals(membership.getMemberId(), parentRequest.getGroupId())) {
326 addKimRoleDelegateRequest(context, parentRequest, member, delegate, role, roleQualifiers);
327 }
328 }
329
330 }
331 }
332 }
333
334
335
336
337
338
339
340
341
342
343
344
345
346 private void addKimRoleDelegateRequest(Context context, ActionRequestValue parentRequest,
347 PeopleFlowMember member, PeopleFlowDelegate delegate, Role role, Map<String, String> roleQualifiers) {
348
349
350 if (delegate.getMemberType() != MemberType.ROLE) {
351 throw new RiceIllegalArgumentException("delegate's member type must be ROLE");
352 } else if (!delegate.getMemberId().equals(role.getId())) {
353 throw new RiceIllegalArgumentException("delegate's member id must match the given role's id");
354 }
355
356 String actionRequestPolicyCode = getDelegateActionRequestPolicyCode(member, delegate);
357
358 List<RoleMembership> memberships = getRoleService().getRoleMembers(Collections.singletonList(
359 delegate.getMemberId()), roleQualifiers);
360
361 if (!CollectionUtils.isEmpty(memberships)) {
362 context.getActionRequestFactory().addDelegateKimRoleRequest(parentRequest,
363 delegate.getDelegationType(), context.getActionRequested().getCode(), member.getPriority(), role,
364 memberships, null, delegate.getResponsibilityId(), true, actionRequestPolicyCode, null);
365 }
366 }
367
368
369
370
371
372
373
374
375
376
377
378 protected List<Map<String, String>> loadRoleQualifiers(Context context, String roleId) {
379 PeopleFlowTypeService peopleFlowTypeService = context.getPeopleFlowTypeService();
380 List<Map<String, String>> roleQualifierList = new ArrayList<Map<String, String>>();
381
382 if (peopleFlowTypeService != null) {
383 Document document = DocumentRouteHeaderValue.to(context.getRouteContext().getDocument());
384 DocumentRouteHeaderValueContent content = new DocumentRouteHeaderValueContent(document.getDocumentId());
385 content.setDocumentContent(context.getRouteContext().getDocumentContent().getDocContent());
386 DocumentContent documentContent = DocumentRouteHeaderValueContent.to(content);
387
388 Map<String, String> roleQualifiers = peopleFlowTypeService.resolveRoleQualifiers(
389 context.getPeopleFlow().getTypeId(), roleId, document, documentContent
390 );
391
392 if (roleQualifiers != null) {
393 roleQualifierList.add(roleQualifiers);
394 }
395
396 boolean versionOk = VersionHelper.compareVersion(context.getPeopleFlowTypeServiceVersion(), CoreConstants.Versions.VERSION_2_3_0) != -1;
397 if(versionOk) {
398 List<Map<String, String>> multipleRoleQualifiers = peopleFlowTypeService.resolveMultipleRoleQualifiers(
399 context.getPeopleFlow().getTypeId(), roleId, document, documentContent);
400
401 if (multipleRoleQualifiers != null) {
402 roleQualifierList.addAll(multipleRoleQualifiers);
403 }
404 }
405
406 }
407
408 return roleQualifierList;
409 }
410
411
412
413
414
415
416
417
418
419
420 private String getDelegateActionRequestPolicyCode(PeopleFlowMember member, PeopleFlowDelegate delegate) {
421 ActionRequestPolicy actionRequestPolicy = delegate.getActionRequestPolicy();
422
423 return (actionRequestPolicy != null) ? actionRequestPolicy.getCode() : getActionRequestPolicyCode(member);
424 }
425
426
427
428
429
430
431
432 private String getActionRequestPolicyCode(PeopleFlowMember member) {
433 ActionRequestPolicy actionRequestPolicy = member.getActionRequestPolicy();
434
435 return (actionRequestPolicy != null) ? actionRequestPolicy.getCode() : null;
436 }
437
438 private Recipient toRecipient(PeopleFlowMember member) {
439 Recipient recipient;
440 if (MemberType.PRINCIPAL == member.getMemberType()) {
441 recipient = new KimPrincipalRecipient(member.getMemberId());
442 } else if (MemberType.GROUP == member.getMemberType()) {
443 recipient = new KimGroupRecipient(member.getMemberId());
444 } else {
445 throw new IllegalStateException("encountered a member type which I did not understand: " +
446 member.getMemberType());
447 }
448 return recipient;
449 }
450
451 private Recipient toRecipient(PeopleFlowDelegate delegate) {
452 Recipient recipient;
453 if (MemberType.PRINCIPAL == delegate.getMemberType()) {
454 recipient = new KimPrincipalRecipient(delegate.getMemberId());
455 } else if (MemberType.GROUP == delegate.getMemberType()) {
456 recipient = new KimGroupRecipient(delegate.getMemberId());
457 } else {
458 throw new IllegalStateException("encountered a delegate member type which I did not understand: " +
459 delegate.getMemberType());
460 }
461 return recipient;
462 }
463
464 public KewTypeRepositoryService getTypeRepositoryService() {
465 return typeRepositoryService;
466 }
467
468 public void setTypeRepositoryService(KewTypeRepositoryService typeRepositoryService) {
469 this.typeRepositoryService = typeRepositoryService;
470 }
471
472 public RoleService getRoleService() {
473 return roleService;
474 }
475
476 public void setRoleService(RoleService roleService) {
477 this.roleService = roleService;
478 }
479
480
481
482
483
484
485
486 private List<ActionRequestValue> findNonRoleRequests(List<ActionRequestValue> actionRequestValues) {
487 List<ActionRequestValue> nonRoleRequests = new ArrayList<ActionRequestValue>();
488
489 return findNonRoleRequests(actionRequestValues, nonRoleRequests);
490 }
491
492
493 private List<ActionRequestValue> findNonRoleRequests(List<ActionRequestValue> actionRequestValues,
494 List<ActionRequestValue> nonRoleRequests) {
495
496 if (!CollectionUtils.isEmpty(actionRequestValues)) {
497 for (ActionRequestValue request : actionRequestValues) if (request.getDelegationType() == null) {
498 if (!CollectionUtils.isEmpty(request.getChildrenRequests())) {
499 findNonRoleRequests(request.getChildrenRequests(), nonRoleRequests);
500 } else {
501
502 if (RecipientType.ROLE.getCode() != request.getRecipientTypeCd()) {
503 nonRoleRequests.add(request);
504 }
505 }
506 }
507 }
508
509 return nonRoleRequests;
510 }
511
512
513
514
515
516
517 final class Context {
518
519 private final RouteContext routeContext;
520 private final PeopleFlowDefinition peopleFlow;
521 private final ActionRequestType actionRequested;
522 private final ActionRequestFactory actionRequestFactory;
523
524
525 private PeopleFlowTypeService peopleFlowTypeService;
526 private boolean peopleFlowTypeServiceLoaded = false;
527 private String peopleFlowTypeServiceVersion;
528
529 Context(RouteContext routeContext, PeopleFlowDefinition peopleFlow, ActionRequestType actionRequested) {
530 if (routeContext == null) {
531 throw new IllegalArgumentException("routeContext was null");
532 }
533 if (peopleFlow == null) {
534 throw new IllegalArgumentException("peopleFlow was null");
535 }
536 if (!peopleFlow.isActive()) {
537 throw new ConfigurationException("Attempted to route to a PeopleFlow that is not active! " + peopleFlow);
538 }
539 if (actionRequested == null) {
540 actionRequested = ActionRequestType.APPROVE;
541 }
542 this.routeContext = routeContext;
543 this.peopleFlow = peopleFlow;
544 this.actionRequested = actionRequested;
545 this.actionRequestFactory = new ActionRequestFactory(routeContext);
546 }
547
548 RouteContext getRouteContext() {
549 return routeContext;
550 }
551
552 PeopleFlowDefinition getPeopleFlow() {
553 return peopleFlow;
554 }
555
556 ActionRequestType getActionRequested() {
557 return actionRequested;
558 }
559
560 ActionRequestFactory getActionRequestFactory() {
561 return actionRequestFactory;
562 }
563
564
565
566
567 PeopleFlowTypeService getPeopleFlowTypeService() {
568 if (peopleFlowTypeServiceLoaded) {
569 return this.peopleFlowTypeService;
570 }
571
572 if (getPeopleFlow().getTypeId() != null) {
573 KewTypeDefinition typeDefinition = getTypeRepositoryService().getTypeById(getPeopleFlow().getTypeId());
574
575 if (typeDefinition == null) {
576 throw new IllegalStateException("Failed to locate a PeopleFlow type for the given type id of '" + getPeopleFlow().getTypeId() + "'");
577 }
578
579 if (StringUtils.isNotBlank(typeDefinition.getServiceName())) {
580 Endpoint endpoint = KsbApiServiceLocator.getServiceBus().getEndpoint(QName.valueOf(typeDefinition.getServiceName()));
581
582 if (endpoint == null) {
583 throw new IllegalStateException("Failed to load the PeopleFlowTypeService with the name '" + typeDefinition.getServiceName() + "'");
584 }
585
586 this.peopleFlowTypeService = (PeopleFlowTypeService)endpoint.getService();
587 this.peopleFlowTypeServiceVersion = endpoint.getServiceConfiguration().getServiceVersion();
588 }
589 }
590 peopleFlowTypeServiceLoaded = true;
591 return this.peopleFlowTypeService;
592 }
593
594 String getPeopleFlowTypeServiceVersion() {
595 if (!this.peopleFlowTypeServiceLoaded) {
596
597 getPeopleFlowTypeService();
598 }
599
600 return this.peopleFlowTypeServiceVersion;
601 }
602 }
603 }