001 /**
002 * Copyright 2005-2012 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.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.krad.document.Document;
060 import org.kuali.rice.krad.rules.TransactionalDocumentRuleBase;
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
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 for ( KimDocumentRoleMember rolePrincipal : role.getRolePrncpls() ) {
427 List<RemotableAttributeError> localErrors = kimTypeService.validateAttributes( role.getKimRoleType().getId(), attributeValidationHelper.convertQualifiersToMap( rolePrincipal.getQualifiers() ) );
428 validationErrors.addAll( attributeValidationHelper.convertErrors(
429 "roles[" + i + "].rolePrncpls[" + j + "]",
430 attributeValidationHelper.convertQualifiersToAttrIdxMap(rolePrincipal.getQualifiers()),
431 localErrors));
432
433 if (uniqueQualifierAttributes.size() > 0) {
434 validateUniquePersonRoleQualifiersUniqueForMembership(role, rolePrincipal, j, uniqueQualifierAttributes, i, validationErrors);
435 }
436
437 j++;
438 }
439 }
440 i++;
441 }
442 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME);
443 if (validationErrors.isEmpty()) {
444 return true;
445 } else {
446 attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors);
447 return false;
448 }
449 }
450
451 /**
452 * Checks all the qualifiers for the given membership, so that all qualifiers which should be unique are guaranteed to be unique
453 *
454 * @param roleIndex the index of the role on the document (for error reporting purposes)
455 * @param membershipToCheckIndex the index of the person's membership in the role (for error reporting purposes)
456 * @return true if all unique values are indeed unique, false otherwise
457 */
458 protected boolean validateUniquePersonRoleQualifiersUniqueForMembership(PersonDocumentRole role, KimDocumentRoleMember membershipToCheck, int membershipToCheckIndex, Set<String> uniqueQualifierAttributes, int roleIndex, List<RemotableAttributeError> validationErrors) {
459 boolean foundError = false;
460 int count = 0;
461
462 for (KimDocumentRoleMember membership : role.getRolePrncpls()) {
463 if (membershipToCheckIndex != count) {
464 if (sameMembershipQualifications(membershipToCheck, membership, uniqueQualifierAttributes)) {
465 foundError = true;
466
467 int qualifierCount = 0;
468
469 for (KimDocumentRoleQualifier qualifier : membership.getQualifiers()) {
470 if (qualifier != null && uniqueQualifierAttributes.contains(qualifier.getKimAttrDefnId())) {
471 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());
472 }
473 qualifierCount += 1;
474 }
475 }
476 }
477
478 count += 1;
479 }
480 return foundError;
481 }
482
483 /**
484 * Determines if two seperate memberships have the same qualifications
485 * @param membershipA the first membership to check
486 * @param membershipB the second membership to check
487 * @param uniqueQualifierAttributes the set of qualifier attributes which need to be unique
488 * @return true if equal, false if otherwise
489 */
490 protected boolean sameMembershipQualifications(KimDocumentRoleMember membershipA, KimDocumentRoleMember membershipB, Set<String> uniqueQualifierAttributes) {
491 boolean equalSoFar = true;
492 for (String uniqueQualifierAttributeDefinitionId : uniqueQualifierAttributes) {
493 final KimDocumentRoleQualifier qualifierA = membershipA.getQualifier(uniqueQualifierAttributeDefinitionId);
494 final KimDocumentRoleQualifier qualifierB = membershipB.getQualifier(uniqueQualifierAttributeDefinitionId);
495
496 if (qualifierA != null && qualifierB != null) {
497 equalSoFar &= (qualifierA.getAttrVal() == null && qualifierB.getAttrVal() == null) || (qualifierA.getAttrVal() == null || qualifierA.getAttrVal().equals(qualifierB.getAttrVal()));
498 }
499 }
500 return equalSoFar;
501 }
502
503 /**
504 * Finds the set of unique qualification attributes for the given role
505 *
506 * @param role the role associated with this person
507 * @param attributeDefinitions the Map of attribute definitions where we can find out if a KimAttribute is supposed to be unique
508 * @return a Set of attribute definition ids for qualifications which are supposed to be unique
509 */
510 public Set<String> findUniqueQualificationAttributes(PersonDocumentRole role, List<KimAttributeField> attributeDefinitions) {
511 Set<String> uniqueQualifications = new HashSet<String>();
512
513 if (role.getRolePrncpls() != null && role.getRolePrncpls().size() > 1) {
514 final KimDocumentRoleMember membership = role.getRolePrncpls().get(0);
515 for (KimDocumentRoleQualifier qualifier: membership.getQualifiers()) {
516 if (qualifier != null && qualifier.getKimAttribute() != null && !StringUtils.isBlank(qualifier.getKimAttribute().getAttributeName())) {
517 final KimAttributeField relatedDefinition = DataDictionaryTypeServiceHelper.findAttributeField(
518 qualifier.getKimAttribute().getAttributeName(), attributeDefinitions);
519
520 if (relatedDefinition != null && relatedDefinition.isUnique()) {
521 uniqueQualifications.add(qualifier.getKimAttrDefnId());
522 }
523 }
524 }
525 }
526
527 return uniqueQualifications;
528 }
529
530 protected boolean validActiveDatesForRole (List<PersonDocumentRole> roles ) {
531 boolean valid = true;
532 int i = 0;
533 for(PersonDocumentRole role : roles ) {
534 int j = 0;
535 for (KimDocumentRoleMember principal : role.getRolePrncpls()) {
536 valid &= validateActiveDate("roles["+i+"].rolePrncpls["+j+"].activeToDate",principal.getActiveFromDate(), principal.getActiveToDate());
537 j++;
538 }
539 i++;
540 }
541 return valid;
542 }
543
544 protected boolean validActiveDatesForGroup (List<PersonDocumentGroup> groups ) {
545 boolean valid = true;
546 int i = 0;
547 for(PersonDocumentGroup group : groups ) {
548 valid &= validateActiveDate("groups["+i+"].activeToDate",group.getActiveFromDate(), group.getActiveToDate());
549 i++;
550 }
551 return valid;
552 }
553
554 protected boolean validActiveDatesForDelegations(List<RoleDocumentDelegationMember> delegationMembers) {
555 boolean valid = true;
556 int i = 0;
557 for(RoleDocumentDelegationMember delegationMember: delegationMembers){
558 valid &= validateActiveDate("delegationMembers["+i+"].activeToDate", delegationMember.getActiveFromDate(), delegationMember.getActiveToDate());
559 i++;
560 }
561 return valid;
562 }
563
564 protected boolean validateActiveDate(String errorPath, Timestamp activeFromDate, Timestamp activeToDate) {
565 // TODO : do not have detail bus rule yet, so just check this for now.
566 boolean valid = true;
567 if (activeFromDate != null && activeToDate !=null && activeToDate.before(activeFromDate)) {
568 GlobalVariables.getMessageMap().putError(errorPath, RiceKeyConstants.ERROR_ACTIVE_TO_DATE_BEFORE_FROM_DATE);
569 valid = false;
570 }
571 return valid;
572 }
573
574 public boolean processAddGroup(AddGroupEvent addGroupEvent) {
575 return getAddGroupRule().processAddGroup(addGroupEvent);
576 }
577
578 public boolean processAddRole(AddRoleEvent addRoleEvent) {
579 return getAddRoleRule().processAddRole(addRoleEvent);
580 }
581
582 public boolean processAddPersonDelegationMember(AddPersonDelegationMemberEvent addPersonDelegationMemberEvent){
583 return getAddPersonDelegationMemberRule().processAddPersonDelegationMember(addPersonDelegationMemberEvent);
584 }
585
586 public IdentityService getIdentityService() {
587 if ( identityService == null ) {
588 identityService = KimApiServiceLocator.getIdentityService();
589 }
590 return identityService;
591 }
592
593 public RoleService getRoleService() {
594 if ( roleService == null ) {
595 roleService = KimApiServiceLocator.getRoleService();
596 }
597 return roleService;
598 }
599
600 public UiDocumentService getUIDocumentService() {
601 if ( uiDocumentService == null ) {
602 uiDocumentService = KIMServiceLocatorInternal.getUiDocumentService();
603 }
604 return uiDocumentService;
605 }
606
607 public IdentityManagementKimDocumentAuthorizer getAuthorizer(IdentityManagementPersonDocument document) {
608 if ( authorizer == null ) {
609 authorizer = (IdentityManagementKimDocumentAuthorizer) KRADServiceLocatorWeb.getDocumentDictionaryService().getDocumentAuthorizer(document);
610 }
611 return authorizer;
612 }
613
614
615
616 /**
617 * @return the addGroupRuleClass
618 */
619 public Class<? extends AddGroupRule> getAddGroupRuleClass() {
620 return this.addGroupRuleClass;
621 }
622
623
624
625 /**
626 * Can be overridden by subclasses to indicate the rule class to use when adding groups.
627 *
628 * @param addGroupRuleClass the addGroupRuleClass to set
629 */
630 public void setAddGroupRuleClass(Class<? extends AddGroupRule> addGroupRuleClass) {
631 this.addGroupRuleClass = addGroupRuleClass;
632 }
633
634
635
636 /**
637 * @return the addRoleRuleClass
638 */
639 public Class<? extends AddRoleRule> getAddRoleRuleClass() {
640 return this.addRoleRuleClass;
641 }
642
643
644
645 /**
646 * Can be overridden by subclasses to indicate the rule class to use when adding roles.
647 *
648 * @param addRoleRuleClass the addRoleRuleClass to set
649 */
650 public void setAddRoleRuleClass(Class<? extends AddRoleRule> addRoleRuleClass) {
651 this.addRoleRuleClass = addRoleRuleClass;
652 }
653
654
655
656 /**
657 * @return the addGroupRule
658 */
659 public AddGroupRule getAddGroupRule() {
660 if ( addGroupRule == null ) {
661 try {
662 addGroupRule = addGroupRuleClass.newInstance();
663 } catch ( Exception ex ) {
664 throw new RuntimeException( "Unable to create AddGroupRule instance using class: " + addGroupRuleClass, ex );
665 }
666 }
667 return addGroupRule;
668 }
669
670
671
672 /**
673 * @return the addRoleRule
674 */
675 public AddRoleRule getAddRoleRule() {
676 if ( addRoleRule == null ) {
677 try {
678 addRoleRule = addRoleRuleClass.newInstance();
679 } catch ( Exception ex ) {
680 throw new RuntimeException( "Unable to create AddRoleRule instance using class: " + addRoleRuleClass, ex );
681 }
682 }
683 return addRoleRule;
684 }
685
686 /**
687 * @return the addRoleRule
688 */
689 public AddPersonDelegationMemberRule getAddPersonDelegationMemberRule() {
690 if(addPersonDelegationMemberRule == null){
691 try {
692 addPersonDelegationMemberRule = addPersonDelegationMemberRuleClass.newInstance();
693 } catch ( Exception ex ) {
694 throw new RuntimeException( "Unable to create AddPersonDelegationMemberRuleClass instance using class: " + addPersonDelegationMemberRuleClass, ex );
695 }
696 }
697 return addPersonDelegationMemberRule;
698 }
699
700 /**
701 * @return the businessObjectService
702 */
703 public BusinessObjectService getBusinessObjectService() {
704 if ( businessObjectService == null ) {
705 businessObjectService = KRADServiceLocator.getBusinessObjectService();
706 }
707 return businessObjectService;
708 }
709
710 public boolean processAddPersonDocumentRoleQualifier(IdentityManagementPersonDocument document, PersonDocumentRole role, KimDocumentRoleMember kimDocumentRoleMember, int selectedRoleIdx) {
711 boolean dateValidationSuccess = validateActiveDate("document.roles[" + selectedRoleIdx + "].newRolePrncpl.activeFromDate", kimDocumentRoleMember.getActiveFromDate(), kimDocumentRoleMember.getActiveToDate());
712 String errorPath = "roles[" + selectedRoleIdx + "].newRolePrncpl";
713 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>();
714 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME);
715 KimTypeService kimTypeService = KimFrameworkServiceLocator.getKimTypeService(KimTypeBo.to(role.getKimRoleType()));
716
717 List<RemotableAttributeError> errorsAttributesAgainstExisting;
718 int i = 0;
719 boolean rulePassed = true;
720 Map<String, String> newMemberQualifiers = attributeValidationHelper.convertQualifiersToMap(kimDocumentRoleMember.getQualifiers());
721 Map<String, String> oldMemberQualifiers;
722 List<String> roleIds = new ArrayList<String>();
723 roleIds.add(role.getRoleId());
724 for(KimDocumentRoleMember member: role.getRolePrncpls()){
725 oldMemberQualifiers = member.getQualifierAsMap();
726 errorsAttributesAgainstExisting = kimTypeService.validateUniqueAttributes(
727 role.getKimRoleType().getId(), newMemberQualifiers, oldMemberQualifiers);
728 validationErrors.addAll(
729 attributeValidationHelper.convertErrors(errorPath, attributeValidationHelper
730 .convertQualifiersToAttrIdxMap(kimDocumentRoleMember.getQualifiers()),
731 errorsAttributesAgainstExisting));
732 i++;
733 }
734
735 if ( kimTypeService != null ) {
736 List<RemotableAttributeError> localErrors = kimTypeService.validateAttributes( role.getKimRoleType().getId(), newMemberQualifiers );
737 validationErrors.addAll( attributeValidationHelper.convertErrors(errorPath,
738 attributeValidationHelper.convertQualifiersToAttrIdxMap(kimDocumentRoleMember.getQualifiers()),
739 localErrors));
740 }
741
742 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME);
743 if (validationErrors.isEmpty()) {
744 rulePassed = dateValidationSuccess;
745 } else {
746 attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors);
747 rulePassed = false;
748 }
749 return rulePassed;
750 }
751
752 protected boolean validateDelegationMemberRoleQualifier(List<RoleDocumentDelegationMember> delegationMembers){
753 List<RemotableAttributeError> validationErrors = new ArrayList<RemotableAttributeError>();
754 boolean valid;
755 int memberCounter = 0;
756 List<RemotableAttributeError> errorsTemp;
757 Map<String, String> mapToValidate;
758 KimTypeService kimTypeService;
759 GlobalVariables.getMessageMap().removeFromErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME);
760 RoleMemberBo roleMember;
761 String errorPath;
762 ArrayList<String> roleIds;
763 KimType kimType;
764 for(RoleDocumentDelegationMember delegationMember: delegationMembers) {
765 kimType = KimTypeBo.to(delegationMember.getRoleBo().getKimRoleType());
766 kimTypeService = KimFrameworkServiceLocator.getKimTypeService(kimType);
767 roleIds = new ArrayList<String>();
768 roleIds.add(delegationMember.getRoleBo().getId());
769 errorPath = "delegationMembers["+memberCounter+"]";
770 mapToValidate = attributeValidationHelper.convertQualifiersToMap(delegationMember.getQualifiers());
771 errorsTemp = kimTypeService.validateAttributes(kimType.getId(), mapToValidate);
772 validationErrors.addAll(
773 attributeValidationHelper.convertErrors(errorPath,
774 attributeValidationHelper.convertQualifiersToAttrIdxMap(delegationMember.getQualifiers()),
775 errorsTemp));
776
777 roleMember = getUIDocumentService().getRoleMember(delegationMember.getRoleMemberId());
778 if(roleMember==null){
779 valid = false;
780 GlobalVariables.getMessageMap().putError("document."+errorPath, RiceKeyConstants.ERROR_DELEGATE_ROLE_MEMBER_ASSOCIATION, new String[]{});
781 } else{
782 kimTypeService.validateUnmodifiableAttributes(kimType.getId(), roleMember.getAttributes(), mapToValidate);
783 validationErrors.addAll(
784 attributeValidationHelper.convertErrors(errorPath, attributeValidationHelper
785 .convertQualifiersToAttrIdxMap(delegationMember.getQualifiers()), errorsTemp));
786 }
787 memberCounter++;
788 }
789 GlobalVariables.getMessageMap().addToErrorPath(KRADConstants.DOCUMENT_PROPERTY_NAME);
790 if (validationErrors.isEmpty()) {
791 valid = true;
792 } else {
793 attributeValidationHelper.moveValidationErrorsToErrorMap(validationErrors);
794 valid = false;
795 }
796 return valid;
797 }
798
799 }