001 /** 002 * Copyright 2005-2012 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.rice.kew.actionrequest; 017 018 import org.apache.commons.collections.CollectionUtils; 019 import org.apache.commons.lang.StringUtils; 020 import org.apache.log4j.Logger; 021 import org.kuali.rice.core.api.delegation.DelegationType; 022 import org.kuali.rice.core.api.exception.RiceRuntimeException; 023 import org.kuali.rice.core.api.membership.MemberType; 024 import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; 025 import org.kuali.rice.kew.actionrequest.service.ActionRequestService; 026 import org.kuali.rice.kew.api.WorkflowRuntimeException; 027 import org.kuali.rice.kew.api.action.ActionRequestPolicy; 028 import org.kuali.rice.kew.api.action.ActionRequestStatus; 029 import org.kuali.rice.kew.api.action.RecipientType; 030 import org.kuali.rice.kew.api.identity.Id; 031 import org.kuali.rice.kew.api.user.UserId; 032 import org.kuali.rice.kew.api.util.CodeTranslator; 033 import org.kuali.rice.kew.engine.RouteContext; 034 import org.kuali.rice.kew.engine.node.RouteNodeInstance; 035 import org.kuali.rice.kew.identity.service.IdentityHelperService; 036 import org.kuali.rice.kew.role.KimRoleRecipient; 037 import org.kuali.rice.kew.role.KimRoleResponsibilityRecipient; 038 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 039 import org.kuali.rice.kew.rule.ResolvedQualifiedRole; 040 import org.kuali.rice.kew.service.KEWServiceLocator; 041 import org.kuali.rice.kew.user.RoleRecipient; 042 import org.kuali.rice.kew.api.KewApiConstants; 043 import org.kuali.rice.kew.util.Utilities; 044 import org.kuali.rice.kew.workgroup.GroupId; 045 import org.kuali.rice.kim.api.common.delegate.DelegateMember; 046 import org.kuali.rice.kim.api.common.delegate.DelegateType; 047 import org.kuali.rice.kim.api.group.Group; 048 import org.kuali.rice.kim.api.group.GroupService; 049 import org.kuali.rice.kim.api.identity.IdentityService; 050 import org.kuali.rice.kim.api.identity.principal.Principal; 051 import org.kuali.rice.kim.api.identity.principal.PrincipalContract; 052 import org.kuali.rice.kim.api.responsibility.ResponsibilityAction; 053 import org.kuali.rice.kim.api.role.Role; 054 import org.kuali.rice.kim.api.role.RoleMembership; 055 import org.kuali.rice.kim.api.role.RoleService; 056 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 057 import org.kuali.rice.krad.util.KRADConstants; 058 import org.kuali.rice.krad.util.ObjectUtils; 059 060 import java.sql.Timestamp; 061 import java.util.ArrayList; 062 import java.util.Collection; 063 import java.util.HashSet; 064 import java.util.Iterator; 065 import java.util.List; 066 import java.util.Map; 067 import java.util.Set; 068 069 070 /** 071 * A factory to aid in creating the ever-so-gnarly ActionRequestValue object. 072 * 073 * @author Kuali Rice Team (rice.collab@kuali.org) 074 */ 075 public class ActionRequestFactory { 076 077 private static final Logger LOG = Logger.getLogger(ActionRequestFactory.class); 078 079 private static RoleService roleService; 080 private static IdentityHelperService identityHelperService; 081 private static IdentityService identityService; 082 private static GroupService groupService; 083 private static ActionRequestService actionRequestService; 084 085 private DocumentRouteHeaderValue document; 086 private RouteNodeInstance routeNode; 087 private List<ActionRequestValue> requestGraphs = new ArrayList<ActionRequestValue>(); 088 089 public ActionRequestFactory() { 090 } 091 092 public ActionRequestFactory(DocumentRouteHeaderValue document) { 093 this.document = document; 094 } 095 096 public ActionRequestFactory(DocumentRouteHeaderValue document, RouteNodeInstance routeNode) { 097 this.document = document; 098 this.routeNode = routeNode; 099 } 100 101 public ActionRequestFactory(RouteContext routeContext) { 102 this(routeContext.getDocument(), routeContext.getNodeInstance()); 103 } 104 105 /** 106 * Constructs ActionRequestValue using default priority and 0 as responsibility 107 * 108 * @param actionRequested 109 * @param recipient 110 * @param description 111 * @param forceAction 112 * @param annotation 113 * @return ActionRequestValue 114 */ 115 public ActionRequestValue createActionRequest(String actionRequested, Recipient recipient, String description, Boolean forceAction, String annotation) { 116 return createActionRequest(actionRequested, new Integer(0), recipient, description, KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, forceAction, annotation); 117 } 118 119 public ActionRequestValue createActionRequest(String actionRequested, Integer priority, Recipient recipient, String description, String responsibilityId, Boolean forceAction, String annotation) { 120 return createActionRequest(actionRequested, priority, recipient, description, responsibilityId, forceAction, null, null, annotation); 121 } 122 123 public ActionRequestValue createActionRequest(String actionRequested, Integer priority, Recipient recipient, String description, String responsibilityId, Boolean forceAction, String approvePolicy, String ruleId, String annotation) { 124 return createActionRequest(actionRequested, priority, recipient, description, responsibilityId, forceAction, approvePolicy, ruleId, annotation, null); 125 } 126 127 public ActionRequestValue createActionRequest(String actionRequested, Integer priority, Recipient recipient, String description, String responsibilityId, Boolean forceAction, String approvePolicy, String ruleId, String annotation, String requestLabel) { 128 ActionRequestValue actionRequest = new ActionRequestValue(); 129 actionRequest.setActionRequested(actionRequested); 130 actionRequest.setDocVersion(document.getDocVersion()); 131 actionRequest.setPriority(priority); 132 actionRequest.setRouteHeader(document); 133 actionRequest.setDocumentId(document.getDocumentId()); 134 actionRequest.setRouteLevel(document.getDocRouteLevel()); 135 actionRequest.setNodeInstance(routeNode); 136 actionRequest.setResponsibilityId(responsibilityId); 137 actionRequest.setResponsibilityDesc(description); 138 actionRequest.setApprovePolicy(approvePolicy); 139 actionRequest.setForceAction(forceAction); 140 actionRequest.setRuleBaseValuesId(ruleId); 141 actionRequest.setAnnotation(annotation); 142 actionRequest.setRequestLabel(requestLabel); 143 setDefaultProperties(actionRequest); 144 resolveRecipient(actionRequest, recipient); 145 146 return actionRequest; 147 } 148 149 public ActionRequestValue createBlankActionRequest() { 150 ActionRequestValue request = new ActionRequestValue(); 151 request.setRouteHeader(document); 152 if (document != null) { 153 request.setDocumentId(document.getDocumentId()); 154 } 155 request.setNodeInstance(routeNode); 156 return request; 157 } 158 159 160 public ActionRequestValue createNotificationRequest(String actionRequestCode, PrincipalContract principal, String reasonActionCode, PrincipalContract reasonActionUser, String responsibilityDesc) { 161 ActionRequestValue request = createActionRequest(actionRequestCode, new KimPrincipalRecipient(principal), responsibilityDesc, Boolean.TRUE, null); 162 String annotation = generateNotificationAnnotation(reasonActionUser, actionRequestCode, reasonActionCode, request); 163 request.setAnnotation(annotation); 164 return request; 165 } 166 167 //unify these 2 methods if possible 168 public List<ActionRequestValue> generateNotifications(List requests, PrincipalContract principal, Recipient delegator, 169 String notificationRequestCode, String actionTakenCode) 170 { 171 String groupName = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KewApiConstants.KEW_NAMESPACE, 172 KRADConstants.DetailTypes.WORKGROUP_DETAIL_TYPE, 173 KewApiConstants.NOTIFICATION_EXCLUDED_USERS_WORKGROUP_NAME_IND); 174 175 176 Group notifyExclusionWorkgroup = null; 177 if(!StringUtils.isBlank(groupName)){ 178 notifyExclusionWorkgroup = getGroupService().getGroupByNamespaceCodeAndName( 179 Utilities.parseGroupNamespaceCode(groupName), Utilities.parseGroupName(groupName)); 180 } 181 182 183 184 return generateNotifications(null, getActionRequestService().getRootRequests(requests), principal, delegator, notificationRequestCode, actionTakenCode, notifyExclusionWorkgroup); 185 } 186 187 private List<ActionRequestValue> generateNotifications(ActionRequestValue parentRequest, 188 List requests, PrincipalContract principal, Recipient delegator, String notificationRequestCode, 189 String actionTakenCode, Group notifyExclusionWorkgroup) 190 { 191 List<ActionRequestValue> notificationRequests = new ArrayList<ActionRequestValue>(); 192 for (Iterator iter = requests.iterator(); iter.hasNext();) 193 { 194 ActionRequestValue actionRequest = (ActionRequestValue) iter.next(); 195 if (!(actionRequest.isRecipientRoutedRequest(principal.getPrincipalId()) || actionRequest.isRecipientRoutedRequest(delegator))) 196 { 197 // skip user requests to system users 198 if ((notifyExclusionWorkgroup != null) && 199 (isRecipientInGroup(notifyExclusionWorkgroup, actionRequest.getRecipient()))) 200 { 201 continue; 202 } 203 ActionRequestValue notificationRequest = createNotificationRequest(actionRequest, principal, notificationRequestCode, actionTakenCode); 204 notificationRequests.add(notificationRequest); 205 if (parentRequest != null) 206 { 207 notificationRequest.setParentActionRequest(parentRequest); 208 parentRequest.getChildrenRequests().add(notificationRequest); 209 } 210 notificationRequests.addAll(generateNotifications(notificationRequest, actionRequest.getChildrenRequests(), principal, delegator, notificationRequestCode, actionTakenCode, notifyExclusionWorkgroup)); 211 } 212 } 213 return notificationRequests; 214 } 215 216 private boolean isRecipientInGroup(Group group, Recipient recipient) 217 { 218 boolean isMember = false; 219 220 if(recipient instanceof KimPrincipalRecipient) 221 { 222 String principalId = ((KimPrincipalRecipient) recipient).getPrincipalId(); 223 String groupId = group.getId(); 224 isMember = getGroupService().isMemberOfGroup(principalId, groupId); 225 } 226 else if (recipient instanceof KimGroupRecipient) 227 { 228 String kimRecipientId = ((KimGroupRecipient) recipient).getGroup().getId(); 229 isMember = getGroupService().isGroupMemberOfGroup(kimRecipientId, group.getId() ); 230 } 231 return isMember; 232 } 233 234 private ActionRequestValue createNotificationRequest(ActionRequestValue actionRequest, PrincipalContract reasonPrincipal, String notificationRequestCode, String actionTakenCode) { 235 236 String annotation = generateNotificationAnnotation(reasonPrincipal, notificationRequestCode, actionTakenCode, actionRequest); 237 ActionRequestValue request = createActionRequest(notificationRequestCode, actionRequest.getPriority(), actionRequest.getRecipient(), actionRequest.getResponsibilityDesc(), KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, Boolean.TRUE, annotation); 238 239 request.setDocVersion(actionRequest.getDocVersion()); 240 request.setApprovePolicy(actionRequest.getApprovePolicy()); 241 request.setRoleName(actionRequest.getRoleName()); 242 request.setQualifiedRoleName(actionRequest.getQualifiedRoleName()); 243 request.setQualifiedRoleNameLabel(actionRequest.getQualifiedRoleNameLabel()); 244 request.setDelegationType(actionRequest.getDelegationType()); 245 return request; 246 } 247 248 private void setDefaultProperties(ActionRequestValue actionRequest) { 249 if (actionRequest.getApprovePolicy() == null) { 250 actionRequest.setApprovePolicy(ActionRequestPolicy.FIRST.getCode()); 251 } 252 actionRequest.setCreateDate(new Timestamp(System.currentTimeMillis())); 253 actionRequest.setCurrentIndicator(Boolean.TRUE); 254 if (actionRequest.getForceAction() == null) { 255 actionRequest.setForceAction(Boolean.FALSE); 256 } 257 if (routeNode != null) { 258 actionRequest.setNodeInstance(routeNode); 259 } 260 actionRequest.setJrfVerNbr(new Integer(0)); 261 actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode()); 262 actionRequest.setRouteHeader(document); 263 actionRequest.setDocumentId(document.getDocumentId()); 264 } 265 266 private static void resolveRecipient(ActionRequestValue actionRequest, Recipient recipient) { 267 if (recipient instanceof KimPrincipalRecipient) { 268 actionRequest.setRecipientTypeCd(RecipientType.PRINCIPAL.getCode()); 269 actionRequest.setPrincipalId(((KimPrincipalRecipient)recipient).getPrincipal().getPrincipalId()); 270 } else if (recipient instanceof KimGroupRecipient) { 271 KimGroupRecipient kimGroupRecipient = (KimGroupRecipient)recipient; 272 actionRequest.setRecipientTypeCd(RecipientType.GROUP.getCode()); 273 actionRequest.setGroupId(kimGroupRecipient.getGroup().getId()); 274 } else if (recipient instanceof RoleRecipient){ 275 RoleRecipient role = (RoleRecipient)recipient; 276 actionRequest.setRecipientTypeCd(RecipientType.ROLE.getCode()); 277 actionRequest.setRoleName(role.getRoleName()); 278 actionRequest.setQualifiedRoleName(role.getQualifiedRoleName()); 279 ResolvedQualifiedRole qualifiedRole = role.getResolvedQualifiedRole(); 280 if (qualifiedRole != null) { 281 actionRequest.setAnnotation(qualifiedRole.getAnnotation() == null ? "" : qualifiedRole.getAnnotation()); 282 actionRequest.setQualifiedRoleNameLabel(qualifiedRole.getQualifiedRoleLabel()); 283 } 284 Recipient targetRecipient = role.getTarget(); 285 if (role.getTarget() != null) { 286 if (targetRecipient instanceof RoleRecipient) { 287 throw new WorkflowRuntimeException("Role Cannot Target a role problem activating request for document " + actionRequest.getDocumentId()); 288 } 289 resolveRecipient(actionRequest, role.getTarget()); 290 } 291 } else if (recipient instanceof KimRoleResponsibilityRecipient) { 292 KimRoleResponsibilityRecipient roleResponsibilityRecipient = (KimRoleResponsibilityRecipient)recipient; 293 actionRequest.setRecipientTypeCd(RecipientType.ROLE.getCode()); 294 actionRequest.setRoleName(roleResponsibilityRecipient.getResponsibilities().get(0).getRoleId()); 295 actionRequest.setQualifiedRoleName( 296 roleResponsibilityRecipient.getResponsibilities().get(0).getResponsibilityName()); 297 // what about qualified role name label? 298 // actionRequest.setAnnotation(roleRecipient.getResponsibilities().get(0).getResponsibilityName()); 299 Recipient targetRecipient = roleResponsibilityRecipient.getTarget(); 300 if (targetRecipient != null) { 301 if (targetRecipient instanceof RoleRecipient) { 302 throw new WorkflowRuntimeException("Role Cannot Target a role problem activating request for document " + actionRequest.getDocumentId()); 303 } 304 resolveRecipient(actionRequest, roleResponsibilityRecipient.getTarget()); 305 } 306 } else if (recipient instanceof KimRoleRecipient) { 307 KimRoleRecipient roleRecipient = (KimRoleRecipient)recipient; 308 actionRequest.setRecipientTypeCd(RecipientType.ROLE.getCode()); 309 Role role = roleRecipient.getRole(); 310 actionRequest.setRoleName(role.getId()); 311 actionRequest.setQualifiedRoleNameLabel(role.getName()); 312 Recipient targetRecipient = roleRecipient.getTarget(); 313 if (targetRecipient != null) { 314 if (targetRecipient instanceof RoleRecipient) { 315 throw new WorkflowRuntimeException("Role Cannot Target a role problem activating request for document " + actionRequest.getDocumentId()); 316 } 317 resolveRecipient(actionRequest, targetRecipient); 318 } 319 } 320 } 321 322 /** 323 * Creates a root Role Request 324 * @param role 325 * @param actionRequested 326 * @param approvePolicy 327 * @param priority 328 * @param responsibilityId 329 * @param forceAction 330 * @param description 331 * @param ruleId 332 * @return the created root role request 333 */ 334 public ActionRequestValue addRoleRequest(RoleRecipient role, String actionRequested, String approvePolicy, Integer priority, String responsibilityId, Boolean forceAction, String description, String ruleId) { 335 336 ActionRequestValue requestGraph = createActionRequest(actionRequested, priority, role, description, responsibilityId, forceAction, approvePolicy, ruleId, null); 337 if (role != null && role.getResolvedQualifiedRole() != null && role.getResolvedQualifiedRole().getRecipients() != null) { 338 int legitimateTargets = 0; 339 for (Iterator<Id> iter = role.getResolvedQualifiedRole().getRecipients().iterator(); iter.hasNext();) { 340 Id recipientId = (Id) iter.next(); 341 if (recipientId.isEmpty()) 342 { 343 throw new WorkflowRuntimeException("Failed to resolve id of type " + recipientId.getClass().getName() + " returned from role '" + role.getRoleName() + "'. Id returned contained a null or empty value."); 344 } 345 if (recipientId instanceof UserId) 346 { 347 Principal principal = getIdentityHelperService().getPrincipal((UserId) recipientId); 348 if(ObjectUtils.isNotNull(principal)) { 349 role.setTarget(new KimPrincipalRecipient(principal)); 350 } 351 } else if (recipientId instanceof GroupId) 352 { 353 role.setTarget(new KimGroupRecipient(getIdentityHelperService().getGroup((GroupId) recipientId))); 354 } else 355 { 356 throw new WorkflowRuntimeException("Could not process the given type of id: " + recipientId.getClass()); 357 } 358 if (role.getTarget() != null) 359 { 360 legitimateTargets++; 361 ActionRequestValue request = createActionRequest(actionRequested, priority, role, description, responsibilityId, forceAction, null, ruleId, null); 362 request.setParentActionRequest(requestGraph); 363 requestGraph.getChildrenRequests().add(request); 364 } 365 } 366 if (legitimateTargets == 0) { 367 LOG.warn("Role did not yield any legitimate recipients"); 368 } 369 } else { 370 LOG.warn("Didn't create action requests for action request description '" + description + "' because of null role or null part of role object graph."); 371 } 372 requestGraphs.add(requestGraph); 373 return requestGraph; 374 } 375 376 /** 377 * Generates an ActionRequest graph for the given KIM Responsibilities. This graph includes any associated delegations. 378 * @param responsibilities 379 * @param approvePolicy 380 */ 381 public void addRoleResponsibilityRequest(List<ResponsibilityAction> responsibilities, String approvePolicy) { 382 if (responsibilities == null || responsibilities.isEmpty()) { 383 LOG.warn("Didn't create action requests for action request description because no responsibilities were defined."); 384 return; 385 } 386 // it's assumed the that all in the list have the same action type code, priority number, etc. 387 String actionTypeCode = responsibilities.get(0).getActionTypeCode(); 388 Integer priority = responsibilities.get(0).getPriorityNumber(); 389 boolean forceAction = responsibilities.get(0).isForceAction(); 390 KimRoleResponsibilityRecipient roleResponsibilityRecipient = new KimRoleResponsibilityRecipient(responsibilities); 391 392 // Creation of a parent graph entry for ???? 393 ActionRequestValue requestGraph = null; 394 StringBuffer parentAnnotation = null; 395 // set to allow for suppression of duplicate annotations on the parent action request 396 Set<String> uniqueChildAnnotations = null; 397 if ( responsibilities.size() > 1 ) { 398 requestGraph = createActionRequest( 399 actionTypeCode, 400 priority, roleResponsibilityRecipient, 401 "", // description 402 KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, 403 forceAction, 404 approvePolicy, 405 null, // ruleId 406 null );// annotation 407 requestGraphs.add(requestGraph); 408 parentAnnotation = new StringBuffer(); 409 uniqueChildAnnotations = new HashSet<String>( responsibilities.size() ); 410 } 411 StringBuffer annotation = new StringBuffer(); 412 for (ResponsibilityAction responsibility : responsibilities) { 413 if ( LOG.isDebugEnabled() ) { 414 LOG.debug( "Processing Responsibility for action request: " + responsibility ); 415 } 416 // KFSMI-2381 - pull information from KIM to populate annotation 417 annotation.setLength( 0 ); 418 Role role = getRoleService().getRole(responsibility.getRoleId()); 419 annotation.append( role.getNamespaceCode() ).append( ' ' ).append( role.getName() ).append( ' ' ); 420 Map<String, String> qualifier = responsibility.getQualifier(); 421 if ( qualifier != null ) { 422 for ( String key : qualifier.keySet() ) { 423 annotation.append( qualifier.get( key ) ).append( ' ' ); 424 } 425 } 426 if (responsibility.getPrincipalId() != null) { 427 roleResponsibilityRecipient.setTarget(new KimPrincipalRecipient(responsibility.getPrincipalId())); 428 } else if (responsibility.getGroupId() != null) { 429 roleResponsibilityRecipient.setTarget(new KimGroupRecipient(responsibility.getGroupId())); 430 } else { 431 throw new RiceRuntimeException("Failed to identify a group or principal on the given ResponsibilityResolutionInfo:" + responsibility); 432 } 433 String annotationStr = annotation.toString(); 434 ActionRequestValue request = createActionRequest( 435 responsibility.getActionTypeCode(), 436 responsibility.getPriorityNumber(), roleResponsibilityRecipient, 437 responsibility.getParallelRoutingGroupingCode(), // description 438 responsibility.getResponsibilityId(), 439 responsibility.isForceAction(), 440 // If not nested in a parent action request, ensure that the request 441 // is first approve so delegations of this request do not require 442 // ALL_APPROVE as well 443 (responsibilities.size() == 1)?ActionRequestPolicy.FIRST.getCode():approvePolicy, 444 null, // ruleId 445 annotationStr); 446 // if there is only a single request, don't create the nesting structure 447 if ( responsibilities.size() > 1 ) { 448 request.setParentActionRequest(requestGraph); 449 requestGraph.getChildrenRequests().add(request); 450 if ( !uniqueChildAnnotations.contains(annotationStr) ) { 451 parentAnnotation.append( annotationStr ).append( " -- " ); 452 uniqueChildAnnotations.add(annotationStr); 453 } 454 } else { 455 requestGraphs.add(request); 456 } 457 generateKimRoleDelegationRequests(responsibility.getDelegates(), request); 458 459 } 460 if ( responsibilities.size() > 1 ) { 461 requestGraph.setAnnotation( StringUtils.chomp( parentAnnotation.toString(), " -- " ) ); 462 } 463 } 464 465 private String generateRoleResponsibilityDelegateAnnotation(DelegateMember member, boolean isPrincipal, boolean isGroup, ActionRequestValue parentRequest) { 466 StringBuffer annotation = new StringBuffer( "Delegation of: " ); 467 annotation.append( parentRequest.getAnnotation() ); 468 annotation.append( " to " ); 469 if (isPrincipal) { 470 annotation.append( "principal " ); 471 Principal principal = getIdentityService().getPrincipal(member.getMemberId()); 472 if ( principal != null ) { 473 annotation.append( principal.getPrincipalName() ); 474 } else { 475 annotation.append( member.getMemberId() ); 476 } 477 } else if (isGroup) { 478 annotation.append( "group " ); 479 Group group = getGroupService().getGroup( member.getMemberId() ); 480 if ( group != null ) { 481 annotation.append( group.getNamespaceCode() ).append( '/' ).append( group.getName() ); 482 } else { 483 annotation.append( member.getMemberId() ); 484 } 485 } else { 486 annotation.append( "?????? '" ); 487 annotation.append( member.getMemberId() ); 488 annotation.append( "'" ); 489 } 490 return annotation.toString(); 491 } 492 493 public ActionRequestValue addDelegationRoleRequest(ActionRequestValue parentRequest, String approvePolicy, RoleRecipient role, String responsibilityId, Boolean forceAction, DelegationType delegationType, String description, String ruleId) { 494 Recipient parentRecipient = parentRequest.getRecipient(); 495 if (parentRecipient instanceof RoleRecipient) { 496 throw new WorkflowRuntimeException("Cannot delegate on Role Request. It must be a request to a person or workgroup, although that request may be in a role"); 497 } 498 if (! relatedToRoot(parentRequest)) { 499 throw new WorkflowRuntimeException("The parent request is not related to any request managed by this factory"); 500 } 501 ActionRequestValue delegationRoleRequest = createActionRequest(parentRequest.getActionRequested(), parentRequest.getPriority(), role, description, responsibilityId, forceAction, approvePolicy, ruleId, null); 502 delegationRoleRequest.setDelegationType(delegationType); 503 int count = 0; 504 for (Iterator<Id> iter = role.getResolvedQualifiedRole().getRecipients().iterator(); iter.hasNext(); count++) { 505 //repeat of createRoleRequest code 506 Id recipientId = iter.next(); 507 if (recipientId.isEmpty()) { 508 throw new WorkflowRuntimeException("Failed to resolve id of type " + recipientId.getClass().getName() + " returned from role '" + role.getRoleName() + "'. Id returned contained a null or empty value."); 509 } 510 if (recipientId instanceof UserId) { 511 role.setTarget(new KimPrincipalRecipient(getIdentityHelperService().getPrincipal((UserId) recipientId))); 512 } else if (recipientId instanceof GroupId) { 513 role.setTarget(new KimGroupRecipient(getIdentityHelperService().getGroup((GroupId) recipientId))); 514 } else { 515 throw new WorkflowRuntimeException("Could not process the given type of id: " + recipientId.getClass()); 516 } 517 ActionRequestValue request = createActionRequest(parentRequest.getActionRequested(), parentRequest.getPriority(), role, description, responsibilityId, forceAction, null, ruleId, null); 518 request.setDelegationType(delegationType); 519 //end repeat 520 request.setParentActionRequest(delegationRoleRequest); 521 delegationRoleRequest.getChildrenRequests().add(request); 522 } 523 524 //put this mini graph in the larger graph 525 if (count > 0) { 526 parentRequest.getChildrenRequests().add(delegationRoleRequest); 527 delegationRoleRequest.setParentActionRequest(parentRequest); 528 } 529 530 return delegationRoleRequest; 531 } 532 533 public ActionRequestValue addDelegationRequest(ActionRequestValue parentRequest, Recipient recipient, String responsibilityId, Boolean forceAction, DelegationType delegationType, String annotation, String ruleId) { 534 if (! relatedToRoot(parentRequest)) { 535 throw new WorkflowRuntimeException("The parent request is not related to any request managed by this factory"); 536 } 537 ActionRequestValue delegationRequest = createActionRequest(parentRequest.getActionRequested(), parentRequest.getPriority(), recipient, parentRequest.getResponsibilityDesc(), responsibilityId, forceAction, null, ruleId, annotation); 538 delegationRequest.setDelegationType(delegationType); 539 540 parentRequest.getChildrenRequests().add(delegationRequest); 541 delegationRequest.setParentActionRequest(parentRequest); 542 543 return delegationRequest; 544 } 545 546 //could probably base behavior off of recipient type 547 public ActionRequestValue addRootActionRequest(String actionRequested, Integer priority, Recipient recipient, String description, String responsibilityId, Boolean forceAction, String approvePolicy, String ruleId) { 548 ActionRequestValue requestGraph = createActionRequest(actionRequested, priority, recipient, description, responsibilityId, forceAction, approvePolicy, ruleId, null); 549 requestGraphs.add(requestGraph); 550 return requestGraph; 551 } 552 553 /** 554 * Generates an ActionRequest graph for the given KIM Responsibilities. This graph includes any associated delegations. 555 */ 556 public void addKimRoleRequest(String actionRequestedCode, Integer priority, Role role, 557 List<RoleMembership> memberships, String description, String responsibilityId, boolean forceAction, 558 String actionRequestPolicyCode, String requestLabel) { 559 if (CollectionUtils.isEmpty(memberships)) { 560 LOG.warn("Didn't create action requests for action request description because no role members were defined for role id " + role.getId()); 561 return; 562 } 563 564 KimRoleRecipient roleRecipient = new KimRoleRecipient(role); 565 566 // Creation of a parent graph entry for ???? 567 ActionRequestValue requestGraph = null; 568 if ( memberships.size() > 1 ) { 569 requestGraph = createActionRequest( 570 actionRequestedCode, 571 priority, 572 roleRecipient, 573 "", // description 574 responsibilityId, 575 forceAction, 576 actionRequestPolicyCode, 577 null, // ruleId 578 null );// annotation 579 requestGraphs.add(requestGraph); 580 } 581 for (RoleMembership membership : memberships) { 582 if ( LOG.isDebugEnabled() ) { 583 LOG.debug( "Processing RoleMembership for action request: " + membership ); 584 } 585 if (MemberType.PRINCIPAL.equals(membership.getType())) { 586 roleRecipient.setTarget(new KimPrincipalRecipient(membership.getMemberId())); 587 } else if (MemberType.GROUP.equals(membership.getType())) { 588 roleRecipient.setTarget(new KimGroupRecipient(membership.getMemberId())); 589 } else { 590 throw new RiceRuntimeException("Failed to identify a group or principal on the given RoleMembership:" + membership); 591 } 592 ActionRequestValue request = createActionRequest( 593 actionRequestedCode, 594 priority, 595 roleRecipient, 596 "", // description 597 responsibilityId, 598 forceAction, 599 // If not nested in a parent action request, ensure that the request 600 // is first approve so delegations of this request do not require 601 // ALL_APPROVE as well 602 (memberships.size() == 1) ? ActionRequestPolicy.FIRST.getCode() : actionRequestPolicyCode, 603 null, // ruleId 604 null); // annotation 605 // if there is only a single request, don't create the nesting structure 606 if ( memberships.size() > 1 ) { 607 request.setParentActionRequest(requestGraph); 608 requestGraph.getChildrenRequests().add(request); 609 } else { 610 requestGraphs.add(request); 611 } 612 generateKimRoleDelegationRequests(membership.getDelegates(), request); 613 } 614 } 615 616 private void generateKimRoleDelegationRequests(List<DelegateType> delegates, ActionRequestValue parentRequest) { 617 for (DelegateType delegate : delegates) { 618 for (DelegateMember member : delegate.getMembers()) { 619 Recipient recipient; 620 boolean isPrincipal = MemberType.PRINCIPAL.equals(member.getType()); 621 boolean isGroup = MemberType.GROUP.equals(member.getType()); 622 if (isPrincipal) { 623 recipient = new KimPrincipalRecipient(member.getMemberId()); 624 } else if (isGroup) { 625 recipient = new KimGroupRecipient(member.getMemberId()); 626 } else { 627 throw new RiceRuntimeException("Invalid DelegateInfo memberTypeCode encountered, was '" + member.getType() + "'"); 628 } 629 String delegationAnnotation = generateRoleResponsibilityDelegateAnnotation(member, isPrincipal, isGroup, parentRequest); 630 addDelegationRequest(parentRequest, recipient, delegate.getDelegationId(), parentRequest.getForceAction(), delegate.getDelegationType(), delegationAnnotation, null); 631 } 632 } 633 } 634 635 //return true if requestGraph (root) is in this requests' parents 636 public boolean relatedToRoot(ActionRequestValue request) { 637 int i = 0; 638 while(i < 3) { 639 if (requestGraphs.contains(request)) { 640 return true; 641 } else if (request == null) { 642 return false; 643 } 644 i++; 645 request = request.getParentActionRequest(); 646 } 647 return false; 648 } 649 650 public List<ActionRequestValue> getRequestGraphs() { 651 //clean up all the trailing role requests with no children - 652 requestGraphs.removeAll(cleanUpChildren(requestGraphs)); 653 return requestGraphs; 654 } 655 656 private Collection<ActionRequestValue> cleanUpChildren(Collection<ActionRequestValue> children) { 657 Collection<ActionRequestValue> requestsToRemove = new ArrayList<ActionRequestValue>(); 658 for (ActionRequestValue aChildren : children) 659 { 660 661 if (aChildren.isRoleRequest()) 662 { 663 if (aChildren.getChildrenRequests().isEmpty()) 664 { 665 requestsToRemove.add(aChildren); 666 } else 667 { 668 Collection<ActionRequestValue> childRequestsToRemove = cleanUpChildren(aChildren.getChildrenRequests()); 669 aChildren.getChildrenRequests().removeAll(childRequestsToRemove); 670 } 671 } 672 } 673 return requestsToRemove; 674 } 675 676 private String generateNotificationAnnotation(PrincipalContract principal, String notificationRequestCode, String actionTakenCode, ActionRequestValue request) { 677 String notification = "Action " + CodeTranslator.getActionRequestLabel(notificationRequestCode) + " generated by Workflow because " + principal.getPrincipalName() + " took action " 678 + CodeTranslator.getActionTakenLabel(actionTakenCode); 679 // FIXME: KULRICE-5201 switched rsp_id to a varchar, so the comparison below is no longer valid 680 // if (request.getResponsibilityId() != null && request.getResponsibilityId() != 0) { 681 // TODO: KULRICE-5329 Verify that this code below makes sense and is sufficient 682 if (request.getResponsibilityId() != null && !KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID.equals(request.getResponsibilityId())) { 683 notification += " Responsibility " + request.getResponsibilityId(); 684 } 685 if (request.getRuleBaseValuesId() != null) { 686 notification += " Rule Id " + request.getRuleBaseValuesId(); 687 } 688 if (request.getAnnotation() != null && request.getAnnotation().length()!=0){ 689 notification += " " + request.getAnnotation(); 690 } 691 return notification; 692 } 693 694 protected static ActionRequestService getActionRequestService() { 695 if ( actionRequestService == null ) { 696 actionRequestService = KEWServiceLocator.getActionRequestService(); 697 } 698 return actionRequestService; 699 } 700 701 /** 702 * @return the roleService 703 */ 704 protected static RoleService getRoleService() { 705 if ( roleService == null ) { 706 roleService = KimApiServiceLocator.getRoleService(); 707 } 708 return roleService; 709 } 710 711 /** 712 * @return the identityHelperService 713 */ 714 protected static IdentityHelperService getIdentityHelperService() { 715 if ( identityHelperService == null ) { 716 identityHelperService = KEWServiceLocator.getIdentityHelperService(); 717 } 718 return identityHelperService; 719 } 720 721 /** 722 * @return the identityService 723 */ 724 protected static IdentityService getIdentityService() { 725 if ( identityService == null ) { 726 identityService = KimApiServiceLocator.getIdentityService(); 727 } 728 return identityService; 729 } 730 731 protected static GroupService getGroupService() { 732 if ( groupService == null ) { 733 groupService = KimApiServiceLocator.getGroupService(); 734 } 735 return groupService; 736 } 737 }