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 }