001 /** 002 * Copyright 2005-2013 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 /** 188 * Generates a notification request for each action request specified, filtering out the specified principal 189 * and delegator, and exclusion workgroup members from notification list 190 * @param parentRequest if non-null, attaches generated notification requests to this parent action request 191 * @param requests list of ActionRequestValues for which to generate corresponding notification requests 192 * @param principal principal to exclude from notifications 193 * @param delegator delegator to exclude from notifications 194 * @param notificationRequestCode the actionrequest code of generated notifications 195 * @param actionTakenCode the actiontaken code to display as the cause of the notification generation 196 * @param notifyExclusionWorkgroup workgroup whose members should not be sent notifications 197 * @return a list of generated notification requests 198 */ 199 private List<ActionRequestValue> generateNotifications(ActionRequestValue parentRequest, 200 List requests, PrincipalContract principal, Recipient delegator, String notificationRequestCode, 201 String actionTakenCode, Group notifyExclusionWorkgroup) 202 { 203 List<ActionRequestValue> notificationRequests = new ArrayList<ActionRequestValue>(); 204 for (Iterator iter = requests.iterator(); iter.hasNext();) 205 { 206 ActionRequestValue actionRequest = (ActionRequestValue) iter.next(); 207 if (!(actionRequest.isRecipientRoutedRequest(principal.getPrincipalId()) || actionRequest.isRecipientRoutedRequest(delegator))) 208 { 209 // skip user requests to system users 210 if ((notifyExclusionWorkgroup != null) && 211 (isRecipientInGroup(notifyExclusionWorkgroup, actionRequest.getRecipient()))) 212 { 213 continue; 214 } 215 ActionRequestValue notificationRequest = createNotificationRequest(actionRequest, principal, notificationRequestCode, actionTakenCode); 216 notificationRequests.add(notificationRequest); 217 if (parentRequest != null) 218 { 219 notificationRequest.setParentActionRequest(parentRequest); 220 parentRequest.getChildrenRequests().add(notificationRequest); 221 } 222 notificationRequests.addAll(generateNotifications(notificationRequest, actionRequest.getChildrenRequests(), principal, delegator, notificationRequestCode, actionTakenCode, notifyExclusionWorkgroup)); 223 } 224 } 225 return notificationRequests; 226 } 227 228 private boolean isRecipientInGroup(Group group, Recipient recipient) 229 { 230 boolean isMember = false; 231 232 if(recipient instanceof KimPrincipalRecipient) 233 { 234 String principalId = ((KimPrincipalRecipient) recipient).getPrincipalId(); 235 String groupId = group.getId(); 236 isMember = getGroupService().isMemberOfGroup(principalId, groupId); 237 } 238 else if (recipient instanceof KimGroupRecipient) 239 { 240 String kimRecipientId = ((KimGroupRecipient) recipient).getGroup().getId(); 241 isMember = getGroupService().isGroupMemberOfGroup(kimRecipientId, group.getId() ); 242 } 243 return isMember; 244 } 245 246 private ActionRequestValue createNotificationRequest(ActionRequestValue actionRequest, PrincipalContract reasonPrincipal, String notificationRequestCode, String actionTakenCode) { 247 248 String annotation = generateNotificationAnnotation(reasonPrincipal, notificationRequestCode, actionTakenCode, actionRequest); 249 ActionRequestValue request = createActionRequest(notificationRequestCode, actionRequest.getPriority(), actionRequest.getRecipient(), actionRequest.getResponsibilityDesc(), KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, Boolean.TRUE, annotation); 250 251 request.setDocVersion(actionRequest.getDocVersion()); 252 request.setApprovePolicy(actionRequest.getApprovePolicy()); 253 request.setRoleName(actionRequest.getRoleName()); 254 request.setQualifiedRoleName(actionRequest.getQualifiedRoleName()); 255 request.setQualifiedRoleNameLabel(actionRequest.getQualifiedRoleNameLabel()); 256 request.setDelegationType(actionRequest.getDelegationType()); 257 return request; 258 } 259 260 private void setDefaultProperties(ActionRequestValue actionRequest) { 261 if (actionRequest.getApprovePolicy() == null) { 262 actionRequest.setApprovePolicy(ActionRequestPolicy.FIRST.getCode()); 263 } 264 actionRequest.setCreateDate(new Timestamp(System.currentTimeMillis())); 265 actionRequest.setCurrentIndicator(Boolean.TRUE); 266 if (actionRequest.getForceAction() == null) { 267 actionRequest.setForceAction(Boolean.FALSE); 268 } 269 if (routeNode != null) { 270 actionRequest.setNodeInstance(routeNode); 271 } 272 actionRequest.setJrfVerNbr(new Integer(0)); 273 actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode()); 274 actionRequest.setRouteHeader(document); 275 actionRequest.setDocumentId(document.getDocumentId()); 276 } 277 278 private static void resolveRecipient(ActionRequestValue actionRequest, Recipient recipient) { 279 if (recipient instanceof KimPrincipalRecipient) { 280 actionRequest.setRecipientTypeCd(RecipientType.PRINCIPAL.getCode()); 281 actionRequest.setPrincipalId(((KimPrincipalRecipient)recipient).getPrincipal().getPrincipalId()); 282 } else if (recipient instanceof KimGroupRecipient) { 283 KimGroupRecipient kimGroupRecipient = (KimGroupRecipient)recipient; 284 actionRequest.setRecipientTypeCd(RecipientType.GROUP.getCode()); 285 actionRequest.setGroupId(kimGroupRecipient.getGroup().getId()); 286 } else if (recipient instanceof RoleRecipient){ 287 RoleRecipient role = (RoleRecipient)recipient; 288 actionRequest.setRecipientTypeCd(RecipientType.ROLE.getCode()); 289 actionRequest.setRoleName(role.getRoleName()); 290 actionRequest.setQualifiedRoleName(role.getQualifiedRoleName()); 291 ResolvedQualifiedRole qualifiedRole = role.getResolvedQualifiedRole(); 292 if (qualifiedRole != null) { 293 actionRequest.setAnnotation(qualifiedRole.getAnnotation() == null ? "" : qualifiedRole.getAnnotation()); 294 actionRequest.setQualifiedRoleNameLabel(qualifiedRole.getQualifiedRoleLabel()); 295 } 296 Recipient targetRecipient = role.getTarget(); 297 if (role.getTarget() != null) { 298 if (targetRecipient instanceof RoleRecipient) { 299 throw new WorkflowRuntimeException("Role Cannot Target a role problem activating request for document " + actionRequest.getDocumentId()); 300 } 301 resolveRecipient(actionRequest, role.getTarget()); 302 } 303 } else if (recipient instanceof KimRoleResponsibilityRecipient) { 304 KimRoleResponsibilityRecipient roleResponsibilityRecipient = (KimRoleResponsibilityRecipient)recipient; 305 actionRequest.setRecipientTypeCd(RecipientType.ROLE.getCode()); 306 actionRequest.setRoleName(roleResponsibilityRecipient.getResponsibilities().get(0).getRoleId()); 307 actionRequest.setQualifiedRoleName( 308 roleResponsibilityRecipient.getResponsibilities().get(0).getResponsibilityName()); 309 // what about qualified role name label? 310 // actionRequest.setAnnotation(roleRecipient.getResponsibilities().get(0).getResponsibilityName()); 311 Recipient targetRecipient = roleResponsibilityRecipient.getTarget(); 312 if (targetRecipient != null) { 313 if (targetRecipient instanceof RoleRecipient) { 314 throw new WorkflowRuntimeException("Role Cannot Target a role problem activating request for document " + actionRequest.getDocumentId()); 315 } 316 resolveRecipient(actionRequest, roleResponsibilityRecipient.getTarget()); 317 } 318 } else if (recipient instanceof KimRoleRecipient) { 319 KimRoleRecipient roleRecipient = (KimRoleRecipient)recipient; 320 actionRequest.setRecipientTypeCd(RecipientType.ROLE.getCode()); 321 Role role = roleRecipient.getRole(); 322 actionRequest.setRoleName(role.getId()); 323 actionRequest.setQualifiedRoleNameLabel(role.getName()); 324 Recipient targetRecipient = roleRecipient.getTarget(); 325 if (targetRecipient != null) { 326 if (targetRecipient instanceof RoleRecipient) { 327 throw new WorkflowRuntimeException("Role Cannot Target a role problem activating request for document " + actionRequest.getDocumentId()); 328 } 329 resolveRecipient(actionRequest, targetRecipient); 330 } 331 } 332 } 333 334 /** 335 * Creates a root Role Request 336 * @param role 337 * @param actionRequested 338 * @param approvePolicy 339 * @param priority 340 * @param responsibilityId 341 * @param forceAction 342 * @param description 343 * @param ruleId 344 * @return the created root role request 345 */ 346 public ActionRequestValue addRoleRequest(RoleRecipient role, String actionRequested, String approvePolicy, Integer priority, String responsibilityId, Boolean forceAction, String description, String ruleId) { 347 348 ActionRequestValue requestGraph = createActionRequest(actionRequested, priority, role, description, responsibilityId, forceAction, approvePolicy, ruleId, null); 349 if (role != null && role.getResolvedQualifiedRole() != null && role.getResolvedQualifiedRole().getRecipients() != null) { 350 int legitimateTargets = 0; 351 for (Iterator<Id> iter = role.getResolvedQualifiedRole().getRecipients().iterator(); iter.hasNext();) { 352 Id recipientId = (Id) iter.next(); 353 if (recipientId.isEmpty()) 354 { 355 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."); 356 } 357 if (recipientId instanceof UserId) 358 { 359 Principal principal = getIdentityHelperService().getPrincipal((UserId) recipientId); 360 if(ObjectUtils.isNotNull(principal)) { 361 role.setTarget(new KimPrincipalRecipient(principal)); 362 } 363 } else if (recipientId instanceof GroupId) 364 { 365 role.setTarget(new KimGroupRecipient(getIdentityHelperService().getGroup((GroupId) recipientId))); 366 } else 367 { 368 throw new WorkflowRuntimeException("Could not process the given type of id: " + recipientId.getClass()); 369 } 370 if (role.getTarget() != null) 371 { 372 legitimateTargets++; 373 ActionRequestValue request = createActionRequest(actionRequested, priority, role, description, responsibilityId, forceAction, null, ruleId, null); 374 request.setParentActionRequest(requestGraph); 375 requestGraph.getChildrenRequests().add(request); 376 } 377 } 378 if (legitimateTargets == 0) { 379 LOG.warn("Role did not yield any legitimate recipients"); 380 } 381 } else { 382 LOG.warn("Didn't create action requests for action request description '" + description + "' because of null role or null part of role object graph."); 383 } 384 requestGraphs.add(requestGraph); 385 return requestGraph; 386 } 387 388 /** 389 * Generates an ActionRequest graph for the given KIM Responsibilities. This graph includes any associated delegations. 390 * @param responsibilities 391 * @param approvePolicy 392 */ 393 public void addRoleResponsibilityRequest(List<ResponsibilityAction> responsibilities, String approvePolicy) { 394 if (responsibilities == null || responsibilities.isEmpty()) { 395 LOG.warn("Didn't create action requests for action request description because no responsibilities were defined."); 396 return; 397 } 398 // it's assumed the that all in the list have the same action type code, priority number, etc. 399 String actionTypeCode = responsibilities.get(0).getActionTypeCode(); 400 Integer priority = responsibilities.get(0).getPriorityNumber(); 401 boolean forceAction = responsibilities.get(0).isForceAction(); 402 KimRoleResponsibilityRecipient roleResponsibilityRecipient = new KimRoleResponsibilityRecipient(responsibilities); 403 404 // Creation of a parent graph entry for ???? 405 ActionRequestValue requestGraph = null; 406 StringBuffer parentAnnotation = null; 407 // set to allow for suppression of duplicate annotations on the parent action request 408 Set<String> uniqueChildAnnotations = null; 409 if ( responsibilities.size() > 1 ) { 410 requestGraph = createActionRequest( 411 actionTypeCode, 412 priority, roleResponsibilityRecipient, 413 "", // description 414 KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID, 415 forceAction, 416 approvePolicy, 417 null, // ruleId 418 null );// annotation 419 requestGraphs.add(requestGraph); 420 parentAnnotation = new StringBuffer(); 421 uniqueChildAnnotations = new HashSet<String>( responsibilities.size() ); 422 } 423 StringBuffer annotation = new StringBuffer(); 424 for (ResponsibilityAction responsibility : responsibilities) { 425 if ( LOG.isDebugEnabled() ) { 426 LOG.debug( "Processing Responsibility for action request: " + responsibility ); 427 } 428 // KFSMI-2381 - pull information from KIM to populate annotation 429 annotation.setLength( 0 ); 430 Role role = getRoleService().getRole(responsibility.getRoleId()); 431 annotation.append( role.getNamespaceCode() ).append( ' ' ).append( role.getName() ).append( ' ' ); 432 Map<String, String> qualifier = responsibility.getQualifier(); 433 if ( qualifier != null ) { 434 for ( String key : qualifier.keySet() ) { 435 annotation.append( qualifier.get( key ) ).append( ' ' ); 436 } 437 } 438 if (responsibility.getPrincipalId() != null) { 439 roleResponsibilityRecipient.setTarget(new KimPrincipalRecipient(responsibility.getPrincipalId())); 440 } else if (responsibility.getGroupId() != null) { 441 roleResponsibilityRecipient.setTarget(new KimGroupRecipient(responsibility.getGroupId())); 442 } else { 443 throw new RiceRuntimeException("Failed to identify a group or principal on the given ResponsibilityResolutionInfo:" + responsibility); 444 } 445 String annotationStr = annotation.toString(); 446 ActionRequestValue request = createActionRequest( 447 responsibility.getActionTypeCode(), 448 responsibility.getPriorityNumber(), roleResponsibilityRecipient, 449 responsibility.getParallelRoutingGroupingCode(), // description 450 responsibility.getResponsibilityId(), 451 responsibility.isForceAction(), 452 // If not nested in a parent action request, ensure that the request 453 // is first approve so delegations of this request do not require 454 // ALL_APPROVE as well 455 (responsibilities.size() == 1)?ActionRequestPolicy.FIRST.getCode():approvePolicy, 456 null, // ruleId 457 annotationStr); 458 // if there is only a single request, don't create the nesting structure 459 if ( responsibilities.size() > 1 ) { 460 request.setParentActionRequest(requestGraph); 461 requestGraph.getChildrenRequests().add(request); 462 if ( !uniqueChildAnnotations.contains(annotationStr) ) { 463 parentAnnotation.append( annotationStr ).append( " -- " ); 464 uniqueChildAnnotations.add(annotationStr); 465 } 466 } else { 467 requestGraphs.add(request); 468 } 469 generateKimRoleDelegationRequests(responsibility.getDelegates(), request); 470 471 } 472 if ( responsibilities.size() > 1 ) { 473 requestGraph.setAnnotation( StringUtils.chomp( parentAnnotation.toString(), " -- " ) ); 474 } 475 } 476 477 private String generateRoleResponsibilityDelegateAnnotation(DelegateMember member, boolean isPrincipal, boolean isGroup, ActionRequestValue parentRequest) { 478 StringBuffer annotation = new StringBuffer( "Delegation of: " ); 479 annotation.append( parentRequest.getAnnotation() ); 480 annotation.append( " to " ); 481 if (isPrincipal) { 482 annotation.append( "principal " ); 483 Principal principal = getIdentityService().getPrincipal(member.getMemberId()); 484 if ( principal != null ) { 485 annotation.append( principal.getPrincipalName() ); 486 } else { 487 annotation.append( member.getMemberId() ); 488 } 489 } else if (isGroup) { 490 annotation.append( "group " ); 491 Group group = getGroupService().getGroup( member.getMemberId() ); 492 if ( group != null ) { 493 annotation.append( group.getNamespaceCode() ).append( '/' ).append( group.getName() ); 494 } else { 495 annotation.append( member.getMemberId() ); 496 } 497 } else { 498 annotation.append( "?????? '" ); 499 annotation.append( member.getMemberId() ); 500 annotation.append( "'" ); 501 } 502 return annotation.toString(); 503 } 504 505 public ActionRequestValue addDelegationRoleRequest(ActionRequestValue parentRequest, String approvePolicy, RoleRecipient role, String responsibilityId, Boolean forceAction, DelegationType delegationType, String description, String ruleId) { 506 Recipient parentRecipient = parentRequest.getRecipient(); 507 if (parentRecipient instanceof RoleRecipient) { 508 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"); 509 } 510 if (! relatedToRoot(parentRequest)) { 511 throw new WorkflowRuntimeException("The parent request is not related to any request managed by this factory"); 512 } 513 ActionRequestValue delegationRoleRequest = createActionRequest(parentRequest.getActionRequested(), parentRequest.getPriority(), role, description, responsibilityId, forceAction, approvePolicy, ruleId, null); 514 delegationRoleRequest.setDelegationType(delegationType); 515 int count = 0; 516 for (Iterator<Id> iter = role.getResolvedQualifiedRole().getRecipients().iterator(); iter.hasNext(); count++) { 517 //repeat of createRoleRequest code 518 Id recipientId = iter.next(); 519 if (recipientId.isEmpty()) { 520 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."); 521 } 522 if (recipientId instanceof UserId) { 523 role.setTarget(new KimPrincipalRecipient(getIdentityHelperService().getPrincipal((UserId) recipientId))); 524 } else if (recipientId instanceof GroupId) { 525 role.setTarget(new KimGroupRecipient(getIdentityHelperService().getGroup((GroupId) recipientId))); 526 } else { 527 throw new WorkflowRuntimeException("Could not process the given type of id: " + recipientId.getClass()); 528 } 529 ActionRequestValue request = createActionRequest(parentRequest.getActionRequested(), parentRequest.getPriority(), role, description, responsibilityId, forceAction, null, ruleId, null); 530 request.setDelegationType(delegationType); 531 //end repeat 532 request.setParentActionRequest(delegationRoleRequest); 533 delegationRoleRequest.getChildrenRequests().add(request); 534 } 535 536 //put this mini graph in the larger graph 537 if (count > 0) { 538 parentRequest.getChildrenRequests().add(delegationRoleRequest); 539 delegationRoleRequest.setParentActionRequest(parentRequest); 540 } 541 542 return delegationRoleRequest; 543 } 544 545 public ActionRequestValue addDelegationRequest(ActionRequestValue parentRequest, Recipient recipient, String responsibilityId, Boolean forceAction, DelegationType delegationType, String annotation, String ruleId) { 546 if (! relatedToRoot(parentRequest)) { 547 throw new WorkflowRuntimeException("The parent request is not related to any request managed by this factory"); 548 } 549 ActionRequestValue delegationRequest = createActionRequest(parentRequest.getActionRequested(), parentRequest.getPriority(), recipient, parentRequest.getResponsibilityDesc(), responsibilityId, forceAction, null, ruleId, annotation); 550 delegationRequest.setDelegationType(delegationType); 551 552 parentRequest.getChildrenRequests().add(delegationRequest); 553 delegationRequest.setParentActionRequest(parentRequest); 554 555 return delegationRequest; 556 } 557 558 //could probably base behavior off of recipient type 559 public ActionRequestValue addRootActionRequest(String actionRequested, Integer priority, Recipient recipient, String description, String responsibilityId, Boolean forceAction, String approvePolicy, String ruleId) { 560 ActionRequestValue requestGraph = createActionRequest(actionRequested, priority, recipient, description, responsibilityId, forceAction, approvePolicy, ruleId, null); 561 requestGraphs.add(requestGraph); 562 return requestGraph; 563 } 564 565 /** 566 * Generates an ActionRequest graph for the given KIM Responsibilities. This graph includes any associated delegations. 567 */ 568 public void addKimRoleRequest(String actionRequestedCode, Integer priority, Role role, 569 List<RoleMembership> memberships, String description, String responsibilityId, boolean forceAction, 570 String actionRequestPolicyCode, String requestLabel) { 571 if (CollectionUtils.isEmpty(memberships)) { 572 LOG.warn("Didn't create action requests for action request description because no role members were defined for role id " + role.getId()); 573 return; 574 } 575 576 KimRoleRecipient roleRecipient = new KimRoleRecipient(role); 577 578 // Creation of a parent graph entry for ???? 579 ActionRequestValue requestGraph = null; 580 if ( memberships.size() > 1 ) { 581 requestGraph = createActionRequest( 582 actionRequestedCode, 583 priority, 584 roleRecipient, 585 "", // description 586 responsibilityId, 587 forceAction, 588 actionRequestPolicyCode, 589 null, // ruleId 590 null );// annotation 591 requestGraphs.add(requestGraph); 592 } 593 for (RoleMembership membership : memberships) { 594 if ( LOG.isDebugEnabled() ) { 595 LOG.debug( "Processing RoleMembership for action request: " + membership ); 596 } 597 if (MemberType.PRINCIPAL.equals(membership.getType())) { 598 roleRecipient.setTarget(new KimPrincipalRecipient(membership.getMemberId())); 599 } else if (MemberType.GROUP.equals(membership.getType())) { 600 roleRecipient.setTarget(new KimGroupRecipient(membership.getMemberId())); 601 } else { 602 throw new RiceRuntimeException("Failed to identify a group or principal on the given RoleMembership:" + membership); 603 } 604 ActionRequestValue request = createActionRequest( 605 actionRequestedCode, 606 priority, 607 roleRecipient, 608 "", // description 609 responsibilityId, 610 forceAction, 611 // If not nested in a parent action request, ensure that the request 612 // is first approve so delegations of this request do not require 613 // ALL_APPROVE as well 614 (memberships.size() == 1) ? ActionRequestPolicy.FIRST.getCode() : actionRequestPolicyCode, 615 null, // ruleId 616 null); // annotation 617 // if there is only a single request, don't create the nesting structure 618 if ( memberships.size() > 1 ) { 619 request.setParentActionRequest(requestGraph); 620 requestGraph.getChildrenRequests().add(request); 621 } else { 622 requestGraphs.add(request); 623 } 624 generateKimRoleDelegationRequests(membership.getDelegates(), request); 625 } 626 } 627 628 private void generateKimRoleDelegationRequests(List<DelegateType> delegates, ActionRequestValue parentRequest) { 629 for (DelegateType delegate : delegates) { 630 for (DelegateMember member : delegate.getMembers()) { 631 Recipient recipient; 632 boolean isPrincipal = MemberType.PRINCIPAL.equals(member.getType()); 633 boolean isGroup = MemberType.GROUP.equals(member.getType()); 634 if (isPrincipal) { 635 recipient = new KimPrincipalRecipient(member.getMemberId()); 636 } else if (isGroup) { 637 recipient = new KimGroupRecipient(member.getMemberId()); 638 } else { 639 throw new RiceRuntimeException("Invalid DelegateInfo memberTypeCode encountered, was '" + member.getType() + "'"); 640 } 641 String delegationAnnotation = generateRoleResponsibilityDelegateAnnotation(member, isPrincipal, isGroup, parentRequest); 642 addDelegationRequest(parentRequest, recipient, delegate.getDelegationId(), parentRequest.getForceAction(), delegate.getDelegationType(), delegationAnnotation, null); 643 } 644 } 645 } 646 647 //return true if requestGraph (root) is in this requests' parents 648 public boolean relatedToRoot(ActionRequestValue request) { 649 int i = 0; 650 while(i < 3) { 651 if (requestGraphs.contains(request)) { 652 return true; 653 } else if (request == null) { 654 return false; 655 } 656 i++; 657 request = request.getParentActionRequest(); 658 } 659 return false; 660 } 661 662 public List<ActionRequestValue> getRequestGraphs() { 663 //clean up all the trailing role requests with no children - 664 requestGraphs.removeAll(cleanUpChildren(requestGraphs)); 665 return requestGraphs; 666 } 667 668 private Collection<ActionRequestValue> cleanUpChildren(Collection<ActionRequestValue> children) { 669 Collection<ActionRequestValue> requestsToRemove = new ArrayList<ActionRequestValue>(); 670 for (ActionRequestValue aChildren : children) 671 { 672 673 if (aChildren.isRoleRequest()) 674 { 675 if (aChildren.getChildrenRequests().isEmpty()) 676 { 677 requestsToRemove.add(aChildren); 678 } else 679 { 680 Collection<ActionRequestValue> childRequestsToRemove = cleanUpChildren(aChildren.getChildrenRequests()); 681 aChildren.getChildrenRequests().removeAll(childRequestsToRemove); 682 } 683 } 684 } 685 return requestsToRemove; 686 } 687 688 private String generateNotificationAnnotation(PrincipalContract principal, String notificationRequestCode, String actionTakenCode, ActionRequestValue request) { 689 String notification = "Action " + CodeTranslator.getActionRequestLabel(notificationRequestCode) + " generated by Workflow because " + principal.getPrincipalName() + " took action " 690 + CodeTranslator.getActionTakenLabel(actionTakenCode); 691 // FIXME: KULRICE-5201 switched rsp_id to a varchar, so the comparison below is no longer valid 692 // if (request.getResponsibilityId() != null && request.getResponsibilityId() != 0) { 693 // TODO: KULRICE-5329 Verify that this code below makes sense and is sufficient 694 if (request.getResponsibilityId() != null && !KewApiConstants.MACHINE_GENERATED_RESPONSIBILITY_ID.equals(request.getResponsibilityId())) { 695 notification += " Responsibility " + request.getResponsibilityId(); 696 } 697 if (request.getRuleBaseValuesId() != null) { 698 notification += " Rule Id " + request.getRuleBaseValuesId(); 699 } 700 if (request.getAnnotation() != null && request.getAnnotation().length()!=0){ 701 notification += " " + request.getAnnotation(); 702 } 703 return notification; 704 } 705 706 protected static ActionRequestService getActionRequestService() { 707 if ( actionRequestService == null ) { 708 actionRequestService = KEWServiceLocator.getActionRequestService(); 709 } 710 return actionRequestService; 711 } 712 713 /** 714 * @return the roleService 715 */ 716 protected static RoleService getRoleService() { 717 if ( roleService == null ) { 718 roleService = KimApiServiceLocator.getRoleService(); 719 } 720 return roleService; 721 } 722 723 /** 724 * @return the identityHelperService 725 */ 726 protected static IdentityHelperService getIdentityHelperService() { 727 if ( identityHelperService == null ) { 728 identityHelperService = KEWServiceLocator.getIdentityHelperService(); 729 } 730 return identityHelperService; 731 } 732 733 /** 734 * @return the identityService 735 */ 736 protected static IdentityService getIdentityService() { 737 if ( identityService == null ) { 738 identityService = KimApiServiceLocator.getIdentityService(); 739 } 740 return identityService; 741 } 742 743 protected static GroupService getGroupService() { 744 if ( groupService == null ) { 745 groupService = KimApiServiceLocator.getGroupService(); 746 } 747 return groupService; 748 } 749 }