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(), member.isForceAction(), 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
138 if (request != null) {
139 roleMemberRequests.add(request);
140 }
141 }
142 }
143
144 return roleMemberRequests;
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 private ActionRequestValue addKimRoleRequest(Context context, PeopleFlowMember member, Role role,
160 Map<String, String> roleQualifiers, boolean ignoreKimDelegates) {
161
162 ActionRequestValue roleMemberRequest = null;
163
164 List<RoleMembership> memberships = getRoleService().getRoleMembers(Collections.singletonList(
165 member.getMemberId()), roleQualifiers);
166
167 String actionRequestPolicyCode = getActionRequestPolicyCode(member);
168
169 if (!CollectionUtils.isEmpty(memberships)) {
170 roleMemberRequest = context.getActionRequestFactory().addKimRoleRequest(
171 context.getActionRequested().getCode(), member.getPriority(), role, memberships, null,
172 member.getResponsibilityId(), member.isForceAction(), actionRequestPolicyCode, null, ignoreKimDelegates);
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 for (PeopleFlowDelegate delegate : member.getDelegates()) {
195 for (ActionRequestValue memberRequest : memberRequests) {
196 if (MemberType.ROLE == delegate.getMemberType()) {
197 generateDelegationToRoleRequests(context, memberRequest, member, delegate);
198 } else {
199 generateDelegationToNonRoleRequest(context, memberRequest, member, delegate);
200 }
201 }
202 }
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216 private void generateDelegationToNonRoleRequest(Context context, ActionRequestValue memberRequest,
217 PeopleFlowMember member, PeopleFlowDelegate delegate) {
218
219 Recipient recipient;
220
221 if (MemberType.PRINCIPAL == delegate.getMemberType()) {
222 recipient = new KimPrincipalRecipient(delegate.getMemberId());
223 } else if (MemberType.GROUP == delegate.getMemberType()) {
224 recipient = new KimGroupRecipient(delegate.getMemberId());
225 } else {
226 throw new RiceIllegalStateException("MemberType unknown: " + delegate.getMemberType());
227 }
228
229 String delegationAnnotation = generateDelegationAnnotation(memberRequest, member, delegate);
230
231 context.getActionRequestFactory().addDelegationRequest(memberRequest, recipient,
232 delegate.getResponsibilityId(), member.isForceAction(),
233 delegate.getDelegationType(), delegationAnnotation, null);
234 }
235
236
237
238
239
240
241
242
243
244 private String generateDelegationAnnotation(ActionRequestValue parentRequest, PeopleFlowMember member,
245 PeopleFlowDelegate delegate) {
246
247 StringBuffer annotation = new StringBuffer( "Delegation of: " );
248 annotation.append( parentRequest.getAnnotation() );
249 annotation.append( " to " );
250
251 if (delegate.getMemberType() == MemberType.PRINCIPAL) {
252 annotation.append( "principal " );
253 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(delegate.getMemberId());
254
255 if ( principal != null ) {
256 annotation.append( principal.getPrincipalName() );
257 } else {
258 annotation.append( member.getMemberId() );
259 }
260 } else if (delegate.getMemberType() == MemberType.GROUP) {
261 annotation.append( "group " );
262 Group group = KimApiServiceLocator.getGroupService().getGroup(delegate.getMemberId());
263
264 if ( group != null ) {
265 annotation.append( group.getNamespaceCode() ).append( '/' ).append( group.getName() );
266 } else {
267 annotation.append( member.getMemberId() );
268 }
269 } else {
270 annotation.append( "?????? '" );
271 annotation.append( member.getMemberId() );
272 annotation.append( "'" );
273 }
274
275 return annotation.toString();
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 protected void generateDelegationToRoleRequests(Context context,
290 ActionRequestValue parentRequest, PeopleFlowMember member, PeopleFlowDelegate delegate) {
291
292 List<Map<String, String>> roleQualifierList = loadRoleQualifiers(context, delegate.getMemberId());
293 Role role = getRoleService().getRole(delegate.getMemberId());
294
295 if (role == null) {
296 throw new IllegalStateException("Failed to locate a role with the given role id of '" +
297 delegate.getMemberId() + "'");
298 }
299
300 if (CollectionUtils.isEmpty(roleQualifierList)) {
301 addKimRoleDelegateRequest(context, parentRequest, member, delegate, role,
302 Collections.<String, String>emptyMap());
303 } else {
304 for (Map<String, String> roleQualifiers : roleQualifierList) {
305 addKimRoleDelegateRequest(context, parentRequest, member, delegate, role, roleQualifiers);
306 }
307 }
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322 private void addKimRoleDelegateRequest(Context context, ActionRequestValue parentRequest,
323 PeopleFlowMember member, PeopleFlowDelegate delegate, Role role, Map<String, String> roleQualifiers) {
324
325
326 if (delegate.getMemberType() != MemberType.ROLE) {
327 throw new RiceIllegalArgumentException("delegate's member type must be ROLE");
328 } else if (!delegate.getMemberId().equals(role.getId())) {
329 throw new RiceIllegalArgumentException("delegate's member id must match the given role's id");
330 }
331
332 String actionRequestPolicyCode = getDelegateActionRequestPolicyCode(member, delegate);
333
334 List<RoleMembership> memberships = getRoleService().getRoleMembers(Collections.singletonList(
335 delegate.getMemberId()), roleQualifiers);
336
337 if (!CollectionUtils.isEmpty(memberships)) {
338 context.getActionRequestFactory().addDelegateKimRoleRequest(parentRequest,
339 delegate.getDelegationType(), context.getActionRequested().getCode(), member.getPriority(), role,
340 memberships, null, delegate.getResponsibilityId(), member.isForceAction(), actionRequestPolicyCode, null);
341 }
342 }
343
344
345
346
347
348
349
350
351
352
353
354 protected List<Map<String, String>> loadRoleQualifiers(Context context, String roleId) {
355 PeopleFlowTypeService peopleFlowTypeService = context.getPeopleFlowTypeService();
356 List<Map<String, String>> roleQualifierList = new ArrayList<Map<String, String>>();
357
358 if (peopleFlowTypeService != null) {
359 Document document = DocumentRouteHeaderValue.to(context.getRouteContext().getDocument());
360 DocumentRouteHeaderValueContent content = new DocumentRouteHeaderValueContent(document.getDocumentId());
361 content.setDocumentContent(context.getRouteContext().getDocumentContent().getDocContent());
362 DocumentContent documentContent = DocumentRouteHeaderValueContent.to(content);
363
364 Map<String, String> roleQualifiers = peopleFlowTypeService.resolveRoleQualifiers(
365 context.getPeopleFlow().getTypeId(), roleId, document, documentContent
366 );
367
368 if (roleQualifiers != null) {
369 roleQualifierList.add(roleQualifiers);
370 }
371
372 boolean versionOk = VersionHelper.compareVersion(context.getPeopleFlowTypeServiceVersion(), CoreConstants.Versions.VERSION_2_3_0) != -1;
373 if(versionOk) {
374 List<Map<String, String>> multipleRoleQualifiers = peopleFlowTypeService.resolveMultipleRoleQualifiers(
375 context.getPeopleFlow().getTypeId(), roleId, document, documentContent);
376
377 if (multipleRoleQualifiers != null) {
378 roleQualifierList.addAll(multipleRoleQualifiers);
379 }
380 }
381
382 }
383
384 return roleQualifierList;
385 }
386
387
388
389
390
391
392
393
394
395
396 private String getDelegateActionRequestPolicyCode(PeopleFlowMember member, PeopleFlowDelegate delegate) {
397 ActionRequestPolicy actionRequestPolicy = delegate.getActionRequestPolicy();
398
399 return (actionRequestPolicy != null) ? actionRequestPolicy.getCode() : getActionRequestPolicyCode(member);
400 }
401
402
403
404
405
406
407
408 private String getActionRequestPolicyCode(PeopleFlowMember member) {
409 ActionRequestPolicy actionRequestPolicy = member.getActionRequestPolicy();
410
411 return (actionRequestPolicy != null) ? actionRequestPolicy.getCode() : null;
412 }
413
414 private Recipient toRecipient(PeopleFlowMember member) {
415 Recipient recipient;
416 if (MemberType.PRINCIPAL == member.getMemberType()) {
417 recipient = new KimPrincipalRecipient(member.getMemberId());
418 } else if (MemberType.GROUP == member.getMemberType()) {
419 recipient = new KimGroupRecipient(member.getMemberId());
420 } else {
421 throw new IllegalStateException("encountered a member type which I did not understand: " +
422 member.getMemberType());
423 }
424 return recipient;
425 }
426
427 private Recipient toRecipient(PeopleFlowDelegate delegate) {
428 Recipient recipient;
429 if (MemberType.PRINCIPAL == delegate.getMemberType()) {
430 recipient = new KimPrincipalRecipient(delegate.getMemberId());
431 } else if (MemberType.GROUP == delegate.getMemberType()) {
432 recipient = new KimGroupRecipient(delegate.getMemberId());
433 } else {
434 throw new IllegalStateException("encountered a delegate member type which I did not understand: " +
435 delegate.getMemberType());
436 }
437 return recipient;
438 }
439
440 public KewTypeRepositoryService getTypeRepositoryService() {
441 return typeRepositoryService;
442 }
443
444 public void setTypeRepositoryService(KewTypeRepositoryService typeRepositoryService) {
445 this.typeRepositoryService = typeRepositoryService;
446 }
447
448 public RoleService getRoleService() {
449 return roleService;
450 }
451
452 public void setRoleService(RoleService roleService) {
453 this.roleService = roleService;
454 }
455
456
457
458
459
460
461
462 private List<ActionRequestValue> findNonRoleRequests(List<ActionRequestValue> actionRequestValues) {
463 List<ActionRequestValue> nonRoleRequests = new ArrayList<ActionRequestValue>();
464
465 return findNonRoleRequests(actionRequestValues, nonRoleRequests);
466 }
467
468
469 private List<ActionRequestValue> findNonRoleRequests(List<ActionRequestValue> actionRequestValues,
470 List<ActionRequestValue> nonRoleRequests) {
471
472 if (!CollectionUtils.isEmpty(actionRequestValues)) {
473 for (ActionRequestValue request : actionRequestValues) if (request.getDelegationType() == null) {
474 if (!CollectionUtils.isEmpty(request.getChildrenRequests())) {
475 findNonRoleRequests(request.getChildrenRequests(), nonRoleRequests);
476 } else {
477
478 if (RecipientType.ROLE.getCode() != request.getRecipientTypeCd()) {
479 nonRoleRequests.add(request);
480 }
481 }
482 }
483 }
484
485 return nonRoleRequests;
486 }
487
488
489
490
491
492
493 final class Context {
494
495 private final RouteContext routeContext;
496 private final PeopleFlowDefinition peopleFlow;
497 private final ActionRequestType actionRequested;
498 private final ActionRequestFactory actionRequestFactory;
499
500
501 private PeopleFlowTypeService peopleFlowTypeService;
502 private boolean peopleFlowTypeServiceLoaded = false;
503 private String peopleFlowTypeServiceVersion;
504
505 Context(RouteContext routeContext, PeopleFlowDefinition peopleFlow, ActionRequestType actionRequested) {
506 if (routeContext == null) {
507 throw new IllegalArgumentException("routeContext was null");
508 }
509 if (peopleFlow == null) {
510 throw new IllegalArgumentException("peopleFlow was null");
511 }
512 if (!peopleFlow.isActive()) {
513 throw new ConfigurationException("Attempted to route to a PeopleFlow that is not active! " + peopleFlow);
514 }
515 if (actionRequested == null) {
516 actionRequested = ActionRequestType.APPROVE;
517 }
518 this.routeContext = routeContext;
519 this.peopleFlow = peopleFlow;
520 this.actionRequested = actionRequested;
521 this.actionRequestFactory = new ActionRequestFactory(routeContext);
522 }
523
524 RouteContext getRouteContext() {
525 return routeContext;
526 }
527
528 PeopleFlowDefinition getPeopleFlow() {
529 return peopleFlow;
530 }
531
532 ActionRequestType getActionRequested() {
533 return actionRequested;
534 }
535
536 ActionRequestFactory getActionRequestFactory() {
537 return actionRequestFactory;
538 }
539
540
541
542
543 PeopleFlowTypeService getPeopleFlowTypeService() {
544 if (peopleFlowTypeServiceLoaded) {
545 return this.peopleFlowTypeService;
546 }
547
548 if (getPeopleFlow().getTypeId() != null) {
549 KewTypeDefinition typeDefinition = getTypeRepositoryService().getTypeById(getPeopleFlow().getTypeId());
550
551 if (typeDefinition == null) {
552 throw new IllegalStateException("Failed to locate a PeopleFlow type for the given type id of '" + getPeopleFlow().getTypeId() + "'");
553 }
554
555 if (StringUtils.isNotBlank(typeDefinition.getServiceName())) {
556 Endpoint endpoint = KsbApiServiceLocator.getServiceBus().getEndpoint(QName.valueOf(typeDefinition.getServiceName()));
557
558 if (endpoint == null) {
559 throw new IllegalStateException("Failed to load the PeopleFlowTypeService with the name '" + typeDefinition.getServiceName() + "'");
560 }
561
562 this.peopleFlowTypeService = (PeopleFlowTypeService)endpoint.getService();
563 this.peopleFlowTypeServiceVersion = endpoint.getServiceConfiguration().getServiceVersion();
564 }
565 }
566 peopleFlowTypeServiceLoaded = true;
567 return this.peopleFlowTypeService;
568 }
569
570 String getPeopleFlowTypeServiceVersion() {
571 if (!this.peopleFlowTypeServiceLoaded) {
572
573 getPeopleFlowTypeService();
574 }
575
576 return this.peopleFlowTypeServiceVersion;
577 }
578 }
579 }