001 /** 002 * Copyright 2005-2014 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.kim.document.rule; 017 018 import org.apache.commons.collections.CollectionUtils; 019 import org.apache.commons.lang.StringUtils; 020 import org.kuali.rice.core.api.uif.RemotableAttributeError; 021 import org.kuali.rice.core.api.util.RiceKeyConstants; 022 import org.kuali.rice.kim.api.identity.IdentityService; 023 import org.kuali.rice.kim.api.identity.entity.EntityDefault; 024 import org.kuali.rice.kim.api.identity.principal.Principal; 025 import org.kuali.rice.kim.api.role.RoleService; 026 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 027 import org.kuali.rice.kim.api.type.KimAttributeField; 028 import org.kuali.rice.kim.api.type.KimType; 029 import org.kuali.rice.kim.bo.ui.KimDocumentRoleMember; 030 import org.kuali.rice.kim.bo.ui.KimDocumentRoleQualifier; 031 import org.kuali.rice.kim.bo.ui.PersonDocumentAffiliation; 032 import org.kuali.rice.kim.bo.ui.PersonDocumentBoDefaultBase; 033 import org.kuali.rice.kim.bo.ui.PersonDocumentEmploymentInfo; 034 import org.kuali.rice.kim.bo.ui.PersonDocumentGroup; 035 import org.kuali.rice.kim.bo.ui.PersonDocumentName; 036 import org.kuali.rice.kim.bo.ui.PersonDocumentRole; 037 import org.kuali.rice.kim.bo.ui.RoleDocumentDelegationMember; 038 import org.kuali.rice.kim.document.IdentityManagementPersonDocument; 039 import org.kuali.rice.kim.document.authorization.IdentityManagementKimDocumentAuthorizer; 040 import org.kuali.rice.kim.framework.services.KimFrameworkServiceLocator; 041 import org.kuali.rice.kim.framework.type.KimTypeService; 042 import org.kuali.rice.kim.impl.KIMPropertyConstants; 043 import org.kuali.rice.kim.impl.identity.principal.PrincipalBo; 044 import org.kuali.rice.kim.impl.role.RoleMemberBo; 045 import org.kuali.rice.kim.impl.type.KimTypeBo; 046 import org.kuali.rice.kim.rule.event.ui.AddGroupEvent; 047 import org.kuali.rice.kim.rule.event.ui.AddPersonDelegationMemberEvent; 048 import org.kuali.rice.kim.rule.event.ui.AddRoleEvent; 049 import org.kuali.rice.kim.rule.ui.AddGroupRule; 050 import org.kuali.rice.kim.rule.ui.AddPersonDelegationMemberRule; 051 import org.kuali.rice.kim.rule.ui.AddPersonDocumentRoleQualifierRule; 052 import org.kuali.rice.kim.rule.ui.AddRoleRule; 053 import org.kuali.rice.kim.rules.ui.PersonDocumentDelegationMemberRule; 054 import org.kuali.rice.kim.rules.ui.PersonDocumentGroupRule; 055 import org.kuali.rice.kim.rules.ui.PersonDocumentRoleRule; 056 import org.kuali.rice.kim.service.KIMServiceLocatorInternal; 057 import org.kuali.rice.kim.service.UiDocumentService; 058 import org.kuali.rice.kns.kim.type.DataDictionaryTypeServiceHelper; 059 import org.kuali.rice.kns.rules.TransactionalDocumentRuleBase; 060 import org.kuali.rice.krad.document.Document; 061 import org.kuali.rice.krad.service.BusinessObjectService; 062 import org.kuali.rice.krad.service.KRADServiceLocator; 063 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 064 import org.kuali.rice.krad.util.GlobalVariables; 065 import org.kuali.rice.krad.util.KRADConstants; 066 import org.kuali.rice.krad.util.ObjectUtils; 067 068 import java.sql.Timestamp; 069 import java.util.ArrayList; 070 import java.util.HashMap; 071 import java.util.HashSet; 072 import java.util.List; 073 import java.util.Map; 074 import java.util.Set; 075 076 /** 077 * This is a description of what this class does - shyu don't forget to fill this in. 078 * 079 * @author Kuali Rice Team (rice.collab@kuali.org) 080 * 081 */ 082 public class IdentityManagementPersonDocumentRule extends TransactionalDocumentRuleBase implements AddGroupRule, AddRoleRule, AddPersonDocumentRoleQualifierRule, AddPersonDelegationMemberRule { 083 084 // protected static final Logger LOG = Logger.getLogger( IdentityManagementPersonDocumentRule.class ); 085 086 protected AddGroupRule addGroupRule; 087 protected AddRoleRule addRoleRule; 088 protected AddPersonDelegationMemberRule addPersonDelegationMemberRule; 089 protected IdentityManagementKimDocumentAuthorizer authorizer; 090 protected BusinessObjectService businessObjectService; 091 protected IdentityService identityService; 092 protected RoleService roleService; 093 protected UiDocumentService uiDocumentService; 094 protected Class<? extends AddGroupRule> addGroupRuleClass = PersonDocumentGroupRule.class; 095 protected Class<? extends AddRoleRule> addRoleRuleClass = PersonDocumentRoleRule.class; 096 protected Class<? extends AddPersonDelegationMemberRule> addPersonDelegationMemberRuleClass = PersonDocumentDelegationMemberRule.class; 097 protected ActiveRoleMemberHelper activeRoleMemberHelper = new ActiveRoleMemberHelper(); 098 protected AttributeValidationHelper attributeValidationHelper = new AttributeValidationHelper(); 099 100 @Override 101 protected boolean processCustomSaveDocumentBusinessRules(Document document) { 102 if (!(document instanceof IdentityManagementPersonDocument)) { 103 return false; 104 } 105 106 IdentityManagementPersonDocument personDoc = (IdentityManagementPersonDocument)document; 107 boolean valid = true; 108 109 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 110 111 //KRADServiceLocatorInternal.getDictionaryValidationService().validateDocument(document); 112 getDictionaryValidationService().validateDocumentAndUpdatableReferencesRecursively(document, getMaxDictionaryValidationDepth(), true, false); 113 valid &= validDuplicatePrincipalName(personDoc); 114 EntityDefault origEntity = getIdentityService().getEntityDefault(personDoc.getEntityId()); 115 boolean isCreatingNew = origEntity==null?true:false; 116 if(getUIDocumentService().canModifyEntity(GlobalVariables.getUserSession().getPrincipalId(), personDoc.getPrincipalId()) || isCreatingNew) { 117 valid &= validateEntityInformation(isCreatingNew, personDoc); 118 } 119 // kimtypeservice.validateAttributes is not working yet. 120 valid &= validateRoleQualifier (personDoc.getRoles()); 121 valid &= validateDelegationMemberRoleQualifier(personDoc.getDelegationMembers()); 122 if (StringUtils.isNotBlank(personDoc.getPrincipalName())) { 123 valid &= doesPrincipalNameExist (personDoc.getPrincipalName(), personDoc.getPrincipalId()); 124 } 125 126 valid &= validActiveDatesForRole (personDoc.getRoles()); 127 valid &= validActiveDatesForGroup (personDoc.getGroups()); 128 valid &= validActiveDatesForDelegations (personDoc.getDelegationMembers()); 129 130 131 // all failed at this point. 132 // valid &= checkUnassignableRoles(personDoc); 133 // valid &= checkUnpopulatableGroups(personDoc); 134 135 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 136 137 return valid; 138 } 139 140 protected boolean validateEntityInformation(boolean isCreatingNew, IdentityManagementPersonDocument personDoc){ 141 boolean valid = true; 142 boolean canOverridePrivacyPreferences = getUIDocumentService().canOverrideEntityPrivacyPreferences(GlobalVariables.getUserSession().getPrincipalId(), personDoc.getPrincipalId()); 143 valid &= checkMultipleDefault (personDoc.getAffiliations(), "affiliations"); 144 if(isCreatingNew || canOverridePrivacyPreferences || !personDoc.getPrivacy().isSuppressName()) { 145 valid &= checkMultipleDefault (personDoc.getNames(), "names"); 146 } 147 if(isCreatingNew || canOverridePrivacyPreferences || !personDoc.getPrivacy().isSuppressAddress()) { 148 valid &= checkMultipleDefault (personDoc.getAddrs(), "addrs"); 149 } 150 if(isCreatingNew || canOverridePrivacyPreferences || !personDoc.getPrivacy().isSuppressPhone()) { 151 valid &= checkMultipleDefault (personDoc.getPhones(), "phones"); 152 } 153 if(isCreatingNew || canOverridePrivacyPreferences || !personDoc.getPrivacy().isSuppressEmail()) { 154 valid &= checkMultipleDefault (personDoc.getEmails(), "emails"); 155 } 156 valid &= checkPrimaryEmploymentInfo (personDoc.getAffiliations()); 157 valid &= validEmployeeIDForAffiliation(personDoc.getAffiliations()); 158 valid &= checkAffiliationTypeChange (personDoc.getAffiliations()); 159 valid &= checkUniqueAffiliationTypePerCampus(personDoc.getAffiliations()); 160 return valid; 161 } 162 163 @SuppressWarnings("unchecked") 164 protected boolean validDuplicatePrincipalName(IdentityManagementPersonDocument personDoc){ 165 Map<String, String> criteria = new HashMap<String, String>(); 166 criteria.put("principalName", personDoc.getPrincipalName()); 167 List<PrincipalBo> prncplImpls = (List<PrincipalBo>)getBusinessObjectService().findMatching(PrincipalBo.class, criteria); 168 boolean rulePassed = true; 169 if(prncplImpls!=null && prncplImpls.size()>0){ 170 if(prncplImpls.size()==1 && prncplImpls.get(0).getPrincipalId().equals(personDoc.getPrincipalId())) { 171 rulePassed = true; 172 } 173 else{ 174 GlobalVariables.getMessageMap().putError("document.principalName", 175 RiceKeyConstants.ERROR_DUPLICATE_ENTRY, new String[] {"Principal Name"}); 176 rulePassed = false; 177 } 178 } 179 return rulePassed; 180 } 181 182 protected boolean checkUnassignableRoles(IdentityManagementPersonDocument document) { 183 boolean valid = true; 184 Map<String,Set<String>> unassignableRoles = getAuthorizer( document ).getUnassignableRoles(document, GlobalVariables.getUserSession().getPerson()); 185 for (String namespaceCode : unassignableRoles.keySet()) { 186 for (String roleName : unassignableRoles.get(namespaceCode)) { 187 int i = 0; 188 for (PersonDocumentRole role : document.getRoles()) { 189 if (role.isEditable() && namespaceCode.endsWith(role.getNamespaceCode()) && roleName.equals(role.getRoleName())) { 190 GlobalVariables.getMessageMap().putError("roles["+i+"].roleId", RiceKeyConstants.ERROR_ASSIGN_ROLE, new String[] {namespaceCode, roleName}); 191 valid = false; 192 } 193 i++; 194 } 195 } 196 } 197 return valid; 198 } 199 200 protected boolean checkUnpopulatableGroups(IdentityManagementPersonDocument document) { 201 boolean valid = true; 202 Map<String,Set<String>> unpopulatableGroups = getAuthorizer( document ).getUnpopulateableGroups(document, GlobalVariables.getUserSession().getPerson()); 203 for (String namespaceCode : unpopulatableGroups.keySet()) { 204 for (String groupName : unpopulatableGroups.get(namespaceCode)) { 205 int i = 0; 206 for (PersonDocumentGroup group : document.getGroups()) { 207 if ( (group.getNamespaceCode() != null && namespaceCode.endsWith(group.getNamespaceCode())) && (group.getGroupName() != null && groupName.equals(group.getGroupName()))) { 208 GlobalVariables.getMessageMap().putError("groups["+i+"].groupId", RiceKeyConstants.ERROR_POPULATE_GROUP, new String[] {namespaceCode, groupName}); 209 } 210 i++; 211 } 212 } 213 valid = false; 214 } 215 return valid; 216 } 217 218 @Override 219 protected boolean processCustomRouteDocumentBusinessRules(Document document) { 220 super.processCustomRouteDocumentBusinessRules(document); 221 IdentityManagementPersonDocument personDoc = (IdentityManagementPersonDocument)document; 222 boolean valid = true; 223 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 224 valid &= validateAffiliationAndName( personDoc ); 225 valid &= checkAffiliationEithOneEMpInfo (personDoc.getAffiliations()); 226 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 227 228 return valid; 229 } 230 231 232 protected boolean checkMultipleDefault (List <? extends PersonDocumentBoDefaultBase> boList, String listName) { 233 boolean valid = true; 234 boolean isDefaultSet = false; 235 int i = 0; 236 for (PersonDocumentBoDefaultBase item : boList) { 237 if (item.isDflt()) { 238 if (isDefaultSet) { 239 GlobalVariables.getMessageMap().putError(listName+"[" + i + "].dflt",RiceKeyConstants.ERROR_MULTIPLE_DEFAULT_SELETION); 240 valid = false; 241 } else { 242 isDefaultSet = true; 243 } 244 } 245 i++; 246 } 247 if (!boList.isEmpty() && !isDefaultSet) { 248 GlobalVariables.getMessageMap().putError(listName+"[0].dflt",RiceKeyConstants.ERROR_NO_DEFAULT_SELETION); 249 } 250 return valid; 251 } 252 253 protected boolean checkPrimaryEmploymentInfo (List <PersonDocumentAffiliation> affiliations) { 254 boolean valid = true; 255 int i = 0; 256 int firstAfflnCounter = -1; 257 boolean isPrimarySet = false; 258 for (PersonDocumentAffiliation affiliation : affiliations) { 259 int j = 0; 260 for (PersonDocumentEmploymentInfo empInfo : affiliation.getEmpInfos()) { 261 if(firstAfflnCounter==-1) { 262 firstAfflnCounter = i; 263 } 264 if (empInfo.isPrimary()) { 265 if (isPrimarySet) { 266 // primary per principal or primary per affiliation ? 267 GlobalVariables.getMessageMap().putError("affiliations[" + i + "].empInfos["+ j +"].primary",RiceKeyConstants.ERROR_MULTIPLE_PRIMARY_EMPLOYMENT); 268 valid = false; 269 } else { 270 isPrimarySet = true; 271 } 272 j++; 273 } 274 } 275 i++; 276 } 277 if(!isPrimarySet && firstAfflnCounter!=-1){ 278 GlobalVariables.getMessageMap().putError("affiliations[" + firstAfflnCounter + "].empInfos[0].primary",RiceKeyConstants.ERROR_NO_PRIMARY_EMPLOYMENT); 279 valid = false; 280 } 281 return valid; 282 } 283 284 protected boolean checkAffiliationTypeChange (List <PersonDocumentAffiliation> affiliations) { 285 boolean valid = true; 286 int i = 0; 287 for (PersonDocumentAffiliation affiliation : affiliations) { 288 if (affiliation.getAffiliationType() != null && !affiliation.getAffiliationTypeCode().equals(affiliation.getAffiliationType().getCode())) { 289 PersonDocumentAffiliation copiedAffiliation = (PersonDocumentAffiliation)ObjectUtils.deepCopy(affiliation); 290 copiedAffiliation.refreshReferenceObject("affiliationType"); 291 if (!copiedAffiliation.getAffiliationType().isEmploymentAffiliationType() && affiliation.getAffiliationType().isEmploymentAffiliationType() && !copiedAffiliation.getEmpInfos().isEmpty()) { 292 GlobalVariables.getMessageMap().putError("affiliations[" + i + "].affiliationTypeCode",RiceKeyConstants.ERROR_NOT_EMPLOYMENT_AFFILIATION_TYPE,new String[] {affiliation.getAffiliationType().getName(), copiedAffiliation.getAffiliationType().getName()}); 293 valid = false; 294 } 295 } 296 i++; 297 } 298 return valid; 299 } 300 301 protected boolean validEmployeeIDForAffiliation(List <PersonDocumentAffiliation> affiliations) { 302 boolean valid = true; 303 int i = 0; 304 int j = 0; 305 for(PersonDocumentAffiliation affiliation : affiliations) { 306 if(affiliation.getAffiliationType() != null && affiliation.getAffiliationType().isEmploymentAffiliationType()){ 307 if(affiliation.getEmpInfos()!=null){ 308 j = 0; 309 for (PersonDocumentEmploymentInfo empInfo : affiliation.getEmpInfos()) { 310 if (StringUtils.isEmpty(empInfo.getEmployeeId())) { 311 GlobalVariables.getMessageMap().putError("affiliations[" + i + "].empInfos["+ j +"].employeeId", RiceKeyConstants.ERROR_REQUIRED_CONDITIONALLY, new String[] {"Employee ID", "an employee"}); 312 valid = false; 313 j++; 314 } 315 } 316 } 317 } 318 i++; 319 } 320 return valid; 321 } 322 323 protected boolean isPersonAnEmployee(List<PersonDocumentAffiliation> affiliations){ 324 boolean isEmployee = false; 325 for (PersonDocumentAffiliation affiliation : affiliations){ 326 if (affiliation.getAffiliationType() != null && affiliation.getAffiliationType().isEmploymentAffiliationType()){ 327 isEmployee = true; 328 break; 329 } 330 } 331 return isEmployee; 332 } 333 334 protected boolean checkUniqueAffiliationTypePerCampus (List <PersonDocumentAffiliation> affiliations) { 335 boolean valid = true; 336 int i = 0; 337 for (PersonDocumentAffiliation affiliation : affiliations) { 338 int j = 0; 339 for (PersonDocumentAffiliation affiliation1 : affiliations) { 340 if (j > i && affiliation.getAffiliationTypeCode() .equals(affiliation1.getAffiliationTypeCode()) && affiliation.getCampusCode().equals(affiliation1.getCampusCode())) { 341 GlobalVariables.getMessageMap().putError("affiliations[" + j + "].affiliationTypeCode",RiceKeyConstants.ERROR_NOT_UNIQUE_AFFILIATION_TYPE_PER_CAMPUE, affiliation.getAffiliationType().getName()); 342 valid = false; 343 } 344 j++; 345 } 346 i++; 347 } 348 return valid; 349 } 350 351 protected boolean checkAffiliationEithOneEMpInfo (List <PersonDocumentAffiliation> affiliations) { 352 boolean valid = true; 353 int i = 0; 354 for (PersonDocumentAffiliation affiliation : affiliations) { 355 if (affiliation.getAffiliationType() .isEmploymentAffiliationType() && affiliation.getEmpInfos().isEmpty()) { 356 GlobalVariables.getMessageMap().putError("affiliations[" + i + "].affiliationTypeCode",RiceKeyConstants.ERROR_ONE_ITEM_REQUIRED, "Employment Information"); 357 valid = false; 358 } 359 i++; 360 } 361 return valid; 362 } 363 364 /* 365 * Verify at least one affiliation and one default name 366 */ 367 protected boolean validateAffiliationAndName(IdentityManagementPersonDocument personDoc) { 368 boolean valid = true; 369 if (personDoc.getAffiliations().isEmpty()) { 370 GlobalVariables.getMessageMap().putError("affiliations[0]",RiceKeyConstants.ERROR_ONE_ITEM_REQUIRED, "affiliation"); 371 valid = false; 372 } 373 if (personDoc.getNames().isEmpty()) { 374 GlobalVariables.getMessageMap().putError("names[0]",RiceKeyConstants.ERROR_ONE_ITEM_REQUIRED, "name"); 375 valid = false; 376 } else{ 377 boolean activeExists = false; 378 for(PersonDocumentName name: personDoc.getNames()){ 379 if(name.isActive()){ 380 activeExists = true; 381 } 382 } 383 if(!activeExists){ 384 GlobalVariables.getMessageMap().putError("names[0]", RiceKeyConstants.ERROR_ONE_ACTIVE_ITEM_REQUIRED, "name"); 385 valid = false; 386 } 387 return valid; 388 389 } 390 return valid; 391 } 392 393 protected boolean doesPrincipalNameExist (String principalName, String principalId) { 394 Principal principal = getIdentityService().getPrincipalByPrincipalName(principalName); 395 if (principal != null && (StringUtils.isBlank(principalId) || !principal.getPrincipalId().equals(principalId))) { 396 GlobalVariables.getMessageMap().putError(KIMPropertyConstants.Person.PRINCIPAL_NAME,RiceKeyConstants.ERROR_EXIST_PRINCIPAL_NAME, principalName); 397 return false; 398 } 399 return true; 400 } 401 402 protected boolean validateRoleQualifier( List<PersonDocumentRole> roles ) { 403 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>(); 404 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 405 int i = 0; 406 for(PersonDocumentRole role : roles ) { 407 KimTypeService kimTypeService = KimFrameworkServiceLocator.getKimTypeService(KimTypeBo.to( 408 role.getKimRoleType())); 409 if(CollectionUtils.isEmpty(role.getRolePrncpls()) && !role.getDefinitions().isEmpty()){ 410 KimType kimTypeInfo = KimApiServiceLocator.getKimTypeInfoService().getKimType(role.getKimRoleType().getId()); 411 Map<String, String> blankQualifiers = attributeValidationHelper.getBlankValueQualifiersMap(kimTypeInfo.getAttributeDefinitions()); 412 List<RemotableAttributeError> localErrors = kimTypeService.validateAttributes( 413 role.getKimRoleType().getId(), blankQualifiers); 414 if(localErrors!=null && !localErrors.isEmpty()){ 415 GlobalVariables.getMessageMap().putError("document.roles["+i+"].newRolePrncpl.qualifiers[0].attrVal", 416 RiceKeyConstants.ERROR_ONE_ITEM_REQUIRED, "Role Qualifier"); 417 return false; 418 } 419 } 420 421 final List<KimAttributeField> attributeDefinitions = role.getDefinitions(); 422 final Set<String> uniqueQualifierAttributes = findUniqueQualificationAttributes(role, attributeDefinitions); 423 424 if ( kimTypeService != null ) { 425 int j = 0; 426 427 for ( KimDocumentRoleMember rolePrincipal : activeRoleMemberHelper.getActiveRoleMembers(role.getRolePrncpls()) ) { 428 List<RemotableAttributeError> localErrors = kimTypeService.validateAttributes( role.getKimRoleType().getId(), attributeValidationHelper.convertQualifiersToMap( rolePrincipal.getQualifiers() ) ); 429 validationErrors.addAll( attributeValidationHelper.convertErrors( 430 "roles[" + i + "].rolePrncpls[" + j + "]", 431 attributeValidationHelper.convertQualifiersToAttrIdxMap(rolePrincipal.getQualifiers()), 432 localErrors)); 433 434 if (uniqueQualifierAttributes.size() > 0) { 435 validateUniquePersonRoleQualifiersUniqueForMembership(role, rolePrincipal, j, uniqueQualifierAttributes, i, validationErrors); 436 } 437 438 j++; 439 } 440 } 441 i++; 442 } 443 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 444 if (validationErrors.isEmpty()) { 445 return true; 446 } else { 447 attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors); 448 return false; 449 } 450 } 451 452 /** 453 * Checks all the qualifiers for the given membership, so that all qualifiers which should be unique are guaranteed to be unique 454 * 455 * @param roleIndex the index of the role on the document (for error reporting purposes) 456 * @param membershipToCheckIndex the index of the person's membership in the role (for error reporting purposes) 457 * @return true if all unique values are indeed unique, false otherwise 458 */ 459 protected boolean validateUniquePersonRoleQualifiersUniqueForMembership(PersonDocumentRole role, KimDocumentRoleMember membershipToCheck, int membershipToCheckIndex, Set<String> uniqueQualifierAttributes, int roleIndex, List<RemotableAttributeError> validationErrors) { 460 boolean foundError = false; 461 int count = 0; 462 463 for (KimDocumentRoleMember membership : role.getRolePrncpls()) { 464 if (sameMembershipQualifications(membershipToCheck, membership, uniqueQualifierAttributes)) { 465 if (count == 0 ) { 466 count +=1; 467 } else { 468 count += 1; 469 foundError = true; 470 471 int qualifierCount = 0; 472 473 for (KimDocumentRoleQualifier qualifier : membership.getQualifiers()) { 474 if (qualifier != null && uniqueQualifierAttributes.contains(qualifier.getKimAttrDefnId())) { 475 validationErrors.add(RemotableAttributeError.Builder.create("document.roles["+roleIndex+"].rolePrncpls["+membershipToCheckIndex+"].qualifiers["+qualifierCount+"].attrVal", RiceKeyConstants.ERROR_DOCUMENT_IDENTITY_MANAGEMENT_PERSON_QUALIFIER_VALUE_NOT_UNIQUE+":"+qualifier.getKimAttribute().getAttributeName()+";"+qualifier.getAttrVal()).build()); 476 } 477 qualifierCount += 1; 478 } 479 } 480 } 481 } 482 return foundError; 483 } 484 485 /** 486 * Determines if two seperate memberships have the same qualifications 487 * @param membershipA the first membership to check 488 * @param membershipB the second membership to check 489 * @param uniqueQualifierAttributes the set of qualifier attributes which need to be unique 490 * @return true if equal, false if otherwise 491 */ 492 protected boolean sameMembershipQualifications(KimDocumentRoleMember membershipA, KimDocumentRoleMember membershipB, Set<String> uniqueQualifierAttributes) { 493 boolean equalSoFar = true; 494 for (String uniqueQualifierAttributeDefinitionId : uniqueQualifierAttributes) { 495 final KimDocumentRoleQualifier qualifierA = membershipA.getQualifier(uniqueQualifierAttributeDefinitionId); 496 final KimDocumentRoleQualifier qualifierB = membershipB.getQualifier(uniqueQualifierAttributeDefinitionId); 497 498 if (qualifierA != null && qualifierB != null) { 499 equalSoFar &= (qualifierA.getAttrVal() == null && qualifierB.getAttrVal() == null) || (qualifierA.getAttrVal() == null || qualifierA.getAttrVal().equals(qualifierB.getAttrVal())); 500 } 501 } 502 return equalSoFar; 503 } 504 505 /** 506 * Finds the set of unique qualification attributes for the given role 507 * 508 * @param role the role associated with this person 509 * @param attributeDefinitions the Map of attribute definitions where we can find out if a KimAttribute is supposed to be unique 510 * @return a Set of attribute definition ids for qualifications which are supposed to be unique 511 */ 512 public Set<String> findUniqueQualificationAttributes(PersonDocumentRole role, List<KimAttributeField> attributeDefinitions) { 513 Set<String> uniqueQualifications = new HashSet<String>(); 514 515 if (role.getRolePrncpls() != null && role.getRolePrncpls().size() > 1) { 516 final KimDocumentRoleMember membership = role.getRolePrncpls().get(0); 517 for (KimDocumentRoleQualifier qualifier: membership.getQualifiers()) { 518 if (qualifier != null && qualifier.getKimAttribute() != null && !StringUtils.isBlank(qualifier.getKimAttribute().getAttributeName())) { 519 final KimAttributeField relatedDefinition = DataDictionaryTypeServiceHelper.findAttributeField( 520 qualifier.getKimAttribute().getAttributeName(), attributeDefinitions); 521 522 if (relatedDefinition != null && relatedDefinition.isUnique()) { 523 uniqueQualifications.add(qualifier.getKimAttrDefnId()); 524 } 525 } 526 } 527 } 528 529 return uniqueQualifications; 530 } 531 532 protected boolean validActiveDatesForRole (List<PersonDocumentRole> roles ) { 533 boolean valid = true; 534 int i = 0; 535 for(PersonDocumentRole role : roles ) { 536 int j = 0; 537 for (KimDocumentRoleMember principal : role.getRolePrncpls()) { 538 valid &= validateActiveDate("roles["+i+"].rolePrncpls["+j+"].activeToDate",principal.getActiveFromDate(), principal.getActiveToDate()); 539 j++; 540 } 541 i++; 542 } 543 return valid; 544 } 545 546 protected boolean validActiveDatesForGroup (List<PersonDocumentGroup> groups ) { 547 boolean valid = true; 548 int i = 0; 549 for(PersonDocumentGroup group : groups ) { 550 valid &= validateActiveDate("groups["+i+"].activeToDate",group.getActiveFromDate(), group.getActiveToDate()); 551 i++; 552 } 553 return valid; 554 } 555 556 protected boolean validActiveDatesForDelegations(List<RoleDocumentDelegationMember> delegationMembers) { 557 boolean valid = true; 558 int i = 0; 559 for(RoleDocumentDelegationMember delegationMember: delegationMembers){ 560 valid &= validateActiveDate("delegationMembers["+i+"].activeToDate", delegationMember.getActiveFromDate(), delegationMember.getActiveToDate()); 561 i++; 562 } 563 return valid; 564 } 565 566 protected boolean validateActiveDate(String errorPath, Timestamp activeFromDate, Timestamp activeToDate) { 567 // TODO : do not have detail bus rule yet, so just check this for now. 568 boolean valid = true; 569 if (activeFromDate != null && activeToDate !=null && activeToDate.before(activeFromDate)) { 570 GlobalVariables.getMessageMap().putError(errorPath, RiceKeyConstants.ERROR_ACTIVE_TO_DATE_BEFORE_FROM_DATE); 571 valid = false; 572 } 573 return valid; 574 } 575 576 public boolean processAddGroup(AddGroupEvent addGroupEvent) { 577 return getAddGroupRule().processAddGroup(addGroupEvent); 578 } 579 580 public boolean processAddRole(AddRoleEvent addRoleEvent) { 581 return getAddRoleRule().processAddRole(addRoleEvent); 582 } 583 584 public boolean processAddPersonDelegationMember(AddPersonDelegationMemberEvent addPersonDelegationMemberEvent){ 585 return getAddPersonDelegationMemberRule().processAddPersonDelegationMember(addPersonDelegationMemberEvent); 586 } 587 588 public IdentityService getIdentityService() { 589 if ( identityService == null ) { 590 identityService = KimApiServiceLocator.getIdentityService(); 591 } 592 return identityService; 593 } 594 595 public RoleService getRoleService() { 596 if ( roleService == null ) { 597 roleService = KimApiServiceLocator.getRoleService(); 598 } 599 return roleService; 600 } 601 602 public UiDocumentService getUIDocumentService() { 603 if ( uiDocumentService == null ) { 604 uiDocumentService = KIMServiceLocatorInternal.getUiDocumentService(); 605 } 606 return uiDocumentService; 607 } 608 609 public IdentityManagementKimDocumentAuthorizer getAuthorizer(IdentityManagementPersonDocument document) { 610 if ( authorizer == null ) { 611 authorizer = (IdentityManagementKimDocumentAuthorizer) KRADServiceLocatorWeb.getDocumentDictionaryService().getDocumentAuthorizer(document); 612 } 613 return authorizer; 614 } 615 616 617 618 /** 619 * @return the addGroupRuleClass 620 */ 621 public Class<? extends AddGroupRule> getAddGroupRuleClass() { 622 return this.addGroupRuleClass; 623 } 624 625 626 627 /** 628 * Can be overridden by subclasses to indicate the rule class to use when adding groups. 629 * 630 * @param addGroupRuleClass the addGroupRuleClass to set 631 */ 632 public void setAddGroupRuleClass(Class<? extends AddGroupRule> addGroupRuleClass) { 633 this.addGroupRuleClass = addGroupRuleClass; 634 } 635 636 637 638 /** 639 * @return the addRoleRuleClass 640 */ 641 public Class<? extends AddRoleRule> getAddRoleRuleClass() { 642 return this.addRoleRuleClass; 643 } 644 645 646 647 /** 648 * Can be overridden by subclasses to indicate the rule class to use when adding roles. 649 * 650 * @param addRoleRuleClass the addRoleRuleClass to set 651 */ 652 public void setAddRoleRuleClass(Class<? extends AddRoleRule> addRoleRuleClass) { 653 this.addRoleRuleClass = addRoleRuleClass; 654 } 655 656 657 658 /** 659 * @return the addGroupRule 660 */ 661 public AddGroupRule getAddGroupRule() { 662 if ( addGroupRule == null ) { 663 try { 664 addGroupRule = addGroupRuleClass.newInstance(); 665 } catch ( Exception ex ) { 666 throw new RuntimeException( "Unable to create AddGroupRule instance using class: " + addGroupRuleClass, ex ); 667 } 668 } 669 return addGroupRule; 670 } 671 672 673 674 /** 675 * @return the addRoleRule 676 */ 677 public AddRoleRule getAddRoleRule() { 678 if ( addRoleRule == null ) { 679 try { 680 addRoleRule = addRoleRuleClass.newInstance(); 681 } catch ( Exception ex ) { 682 throw new RuntimeException( "Unable to create AddRoleRule instance using class: " + addRoleRuleClass, ex ); 683 } 684 } 685 return addRoleRule; 686 } 687 688 /** 689 * @return the addRoleRule 690 */ 691 public AddPersonDelegationMemberRule getAddPersonDelegationMemberRule() { 692 if(addPersonDelegationMemberRule == null){ 693 try { 694 addPersonDelegationMemberRule = addPersonDelegationMemberRuleClass.newInstance(); 695 } catch ( Exception ex ) { 696 throw new RuntimeException( "Unable to create AddPersonDelegationMemberRuleClass instance using class: " + addPersonDelegationMemberRuleClass, ex ); 697 } 698 } 699 return addPersonDelegationMemberRule; 700 } 701 702 /** 703 * @return the businessObjectService 704 */ 705 public BusinessObjectService getBusinessObjectService() { 706 if ( businessObjectService == null ) { 707 businessObjectService = KRADServiceLocator.getBusinessObjectService(); 708 } 709 return businessObjectService; 710 } 711 712 public boolean processAddPersonDocumentRoleQualifier(IdentityManagementPersonDocument document, PersonDocumentRole role, KimDocumentRoleMember kimDocumentRoleMember, int selectedRoleIdx) { 713 boolean dateValidationSuccess = validateActiveDate("document.roles[" + selectedRoleIdx + "].newRolePrncpl.activeFromDate", kimDocumentRoleMember.getActiveFromDate(), kimDocumentRoleMember.getActiveToDate()); 714 String errorPath = "roles[" + selectedRoleIdx + "].newRolePrncpl"; 715 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>(); 716 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 717 KimTypeService kimTypeService = KimFrameworkServiceLocator.getKimTypeService(KimTypeBo.to(role.getKimRoleType())); 718 719 List<RemotableAttributeError> errorsAttributesAgainstExisting; 720 int i = 0; 721 boolean rulePassed = true; 722 Map<String, String> newMemberQualifiers = attributeValidationHelper.convertQualifiersToMap(kimDocumentRoleMember.getQualifiers()); 723 Map<String, String> oldMemberQualifiers; 724 List<String> roleIds = new ArrayList<String>(); 725 roleIds.add(role.getRoleId()); 726 for(KimDocumentRoleMember member: role.getRolePrncpls()){ 727 oldMemberQualifiers = member.getQualifierAsMap(); 728 errorsAttributesAgainstExisting = kimTypeService.validateUniqueAttributes( 729 role.getKimRoleType().getId(), newMemberQualifiers, oldMemberQualifiers); 730 validationErrors.addAll( 731 attributeValidationHelper.convertErrors(errorPath, attributeValidationHelper 732 .convertQualifiersToAttrIdxMap(kimDocumentRoleMember.getQualifiers()), 733 errorsAttributesAgainstExisting)); 734 i++; 735 } 736 737 if ( kimTypeService != null ) { 738 List<RemotableAttributeError> localErrors = kimTypeService.validateAttributes( role.getKimRoleType().getId(), newMemberQualifiers ); 739 validationErrors.addAll( attributeValidationHelper.convertErrors(errorPath, 740 attributeValidationHelper.convertQualifiersToAttrIdxMap(kimDocumentRoleMember.getQualifiers()), 741 localErrors)); 742 } 743 744 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 745 if (validationErrors.isEmpty()) { 746 rulePassed = dateValidationSuccess; 747 } else { 748 attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors); 749 rulePassed = false; 750 } 751 return rulePassed; 752 } 753 754 protected boolean validateDelegationMemberRoleQualifier(List<RoleDocumentDelegationMember> delegationMembers){ 755 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>(); 756 boolean valid; 757 int memberCounter = 0; 758 List<RemotableAttributeError> errorsTemp; 759 Map<String, String> mapToValidate; 760 KimTypeService kimTypeService; 761 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 762 RoleMemberBo roleMember; 763 String errorPath; 764 ArrayList<String> roleIds; 765 KimType kimType; 766 for(RoleDocumentDelegationMember delegationMember: delegationMembers) { 767 kimType = KimTypeBo.to(delegationMember.getRoleBo().getKimRoleType()); 768 kimTypeService = KimFrameworkServiceLocator.getKimTypeService(kimType); 769 roleIds = new ArrayList<String>(); 770 roleIds.add(delegationMember.getRoleBo().getId()); 771 errorPath = "delegationMembers["+memberCounter+"]"; 772 mapToValidate = attributeValidationHelper.convertQualifiersToMap(delegationMember.getQualifiers()); 773 errorsTemp = kimTypeService.validateAttributes(kimType.getId(), mapToValidate); 774 validationErrors.addAll( 775 attributeValidationHelper.convertErrors(errorPath, 776 attributeValidationHelper.convertQualifiersToAttrIdxMap(delegationMember.getQualifiers()), 777 errorsTemp)); 778 779 roleMember = getUIDocumentService().getRoleMember(delegationMember.getRoleMemberId()); 780 if(roleMember==null){ 781 valid = false; 782 GlobalVariables.getMessageMap().putError("document."+errorPath, RiceKeyConstants.ERROR_DELEGATE_ROLE_MEMBER_ASSOCIATION, new String[]{}); 783 } else{ 784 kimTypeService.validateUnmodifiableAttributes(kimType.getId(), roleMember.getAttributes(), mapToValidate); 785 validationErrors.addAll( 786 attributeValidationHelper.convertErrors(errorPath, attributeValidationHelper 787 .convertQualifiersToAttrIdxMap(delegationMember.getQualifiers()), errorsTemp)); 788 } 789 memberCounter++; 790 } 791 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME); 792 if (validationErrors.isEmpty()) { 793 valid = true; 794 } else { 795 attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors); 796 valid = false; 797 } 798 return valid; 799 } 800 801 }