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 }