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