1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kim.impl.identity;
17
18 import org.apache.commons.beanutils.PropertyUtils;
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.kuali.rice.core.api.CoreApiServiceLocator;
22 import org.kuali.rice.core.api.criteria.Predicate;
23 import org.kuali.rice.core.api.criteria.PredicateUtils;
24 import org.kuali.rice.core.api.criteria.QueryByCriteria;
25 import org.kuali.rice.kim.api.identity.IdentityService;
26 import org.kuali.rice.kim.api.identity.Person;
27 import org.kuali.rice.kim.api.identity.PersonService;
28 import org.kuali.rice.kim.api.identity.entity.EntityDefault;
29 import org.kuali.rice.kim.api.identity.entity.EntityDefaultQueryResults;
30 import org.kuali.rice.kim.api.identity.external.EntityExternalIdentifierType;
31 import org.kuali.rice.kim.api.identity.principal.Principal;
32 import org.kuali.rice.kim.api.identity.type.EntityTypeContactInfoDefault;
33 import org.kuali.rice.kim.api.role.RoleService;
34 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
35 import org.kuali.rice.kim.impl.KIMPropertyConstants;
36 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
37 import org.kuali.rice.kns.service.KNSServiceLocator;
38 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
39 import org.kuali.rice.krad.bo.BusinessObject;
40 import org.kuali.rice.krad.bo.DataObjectRelationship;
41 import org.kuali.rice.krad.lookup.CollectionIncomplete;
42 import org.kuali.rice.krad.util.KRADConstants;
43 import org.kuali.rice.krad.util.KRADPropertyConstants;
44 import org.kuali.rice.krad.util.ObjectUtils;
45
46 import java.security.GeneralSecurityException;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Set;
56
57
58
59
60
61
62
63 public class PersonServiceImpl implements PersonService {
64
65 private static Logger LOG = Logger.getLogger( PersonServiceImpl.class );
66 protected static final String ENTITY_EXT_ID_PROPERTY_PREFIX = "externalIdentifiers.";
67 protected static final String ENTITY_AFFILIATION_PROPERTY_PREFIX = "affiliations.";
68 protected static final String ENTITY_TYPE_PROPERTY_PREFIX = "entityTypeContactInfos.";
69 protected static final String ENTITY_EMAIL_PROPERTY_PREFIX = "entityTypeContactInfos.emailAddresses.";
70 protected static final String ENTITY_PHONE_PROPERTY_PREFIX = "entityTypeContactInfos.phoneNumbers.";
71 protected static final String ENTITY_ADDRESS_PROPERTY_PREFIX = "entityTypeContactInfos.addresses.";
72 protected static final String ENTITY_NAME_PROPERTY_PREFIX = "names.";
73 protected static final String PRINCIPAL_PROPERTY_PREFIX = "principals.";
74 protected static final String ENTITY_EMPLOYEE_ID_PROPERTY_PREFIX = "employmentInformation.";
75
76 protected static final String EXTENSION = "extension";
77
78 private IdentityService identityService;
79 private RoleService roleService;
80 private BusinessObjectMetaDataService businessObjectMetaDataService;
81 private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
82
83 protected List<String> personEntityTypeCodes = new ArrayList<String>( 4 );
84
85 private String personEntityTypeLookupCriteria = null;
86
87 protected Map<String,String> baseLookupCriteria = new HashMap<String,String>();
88 protected Map<String,String> criteriaConversion = new HashMap<String,String>();
89 protected ArrayList<String> personCachePropertyNames = new ArrayList<String>();
90 {
91
92
93 baseLookupCriteria.put( KIMPropertyConstants.Person.ACTIVE, "Y" );
94 baseLookupCriteria.put( ENTITY_TYPE_PROPERTY_PREFIX + KRADPropertyConstants.ACTIVE, "Y" );
95
96
97 criteriaConversion.put( KIMPropertyConstants.Person.ENTITY_ID, KIMPropertyConstants.Entity.ID);
98 criteriaConversion.put( KIMPropertyConstants.Person.ACTIVE, PRINCIPAL_PROPERTY_PREFIX + KRADPropertyConstants.ACTIVE );
99 criteriaConversion.put( KIMPropertyConstants.Person.PRINCIPAL_ID, PRINCIPAL_PROPERTY_PREFIX + KIMPropertyConstants.Person.PRINCIPAL_ID );
100 criteriaConversion.put( KIMPropertyConstants.Person.PRINCIPAL_NAME, PRINCIPAL_PROPERTY_PREFIX + KIMPropertyConstants.Person.PRINCIPAL_NAME );
101 criteriaConversion.put( KIMPropertyConstants.Person.FIRST_NAME, "names.firstName" );
102 criteriaConversion.put( KIMPropertyConstants.Person.LAST_NAME, "names.lastName" );
103 criteriaConversion.put( KIMPropertyConstants.Person.MIDDLE_NAME, "names.middleName" );
104 criteriaConversion.put( KIMPropertyConstants.Person.EMAIL_ADDRESS, "entityTypeContactInfos.emailAddresses.emailAddress" );
105 criteriaConversion.put( KIMPropertyConstants.Person.PHONE_NUMBER, "entityTypeContactInfos.phoneNumbers.phoneNumber" );
106 criteriaConversion.put( KIMPropertyConstants.Person.ADDRESS_LINE_1, "entityTypeContactInfos.addresses.line1" );
107 criteriaConversion.put( KIMPropertyConstants.Person.ADDRESS_LINE_2, "entityTypeContactInfos.addresses.line2" );
108 criteriaConversion.put( KIMPropertyConstants.Person.ADDRESS_LINE_3, "entityTypeContactInfos.addresses.line3" );
109 criteriaConversion.put( KIMPropertyConstants.Person.CITY, "entityTypeContactInfos.addresses.city" );
110 criteriaConversion.put( KIMPropertyConstants.Person.STATE_CODE, "entityTypeContactInfos.addresses.stateProvinceCode" );
111 criteriaConversion.put( KIMPropertyConstants.Person.POSTAL_CODE, "entityTypeContactInfos.addresses.postalCode" );
112 criteriaConversion.put( KIMPropertyConstants.Person.COUNTRY_CODE, "entityTypeContactInfos.addresses.countryCode" );
113 criteriaConversion.put( KIMPropertyConstants.Person.CAMPUS_CODE, "affiliations.campusCode" );
114 criteriaConversion.put( KIMPropertyConstants.Person.AFFILIATION_TYPE_CODE, "affiliations.affiliationTypeCode" );
115 criteriaConversion.put( KIMPropertyConstants.Person.EXTERNAL_IDENTIFIER_TYPE_CODE, "externalIdentifiers.externalIdentifierTypeCode" );
116 criteriaConversion.put( KIMPropertyConstants.Person.EXTERNAL_ID, "externalIdentifiers.externalId" );
117 criteriaConversion.put( KIMPropertyConstants.Person.EMPLOYEE_TYPE_CODE, "employmentInformation.employeeTypeCode" );
118 criteriaConversion.put( KIMPropertyConstants.Person.EMPLOYEE_STATUS_CODE, "employmentInformation.employeeStatusCode" );
119 criteriaConversion.put( KIMPropertyConstants.Person.EMPLOYEE_ID, "employmentInformation.employeeId" );
120 criteriaConversion.put( KIMPropertyConstants.Person.BASE_SALARY_AMOUNT, "employmentInformation.baseSalaryAmount" );
121 criteriaConversion.put( KIMPropertyConstants.Person.PRIMARY_DEPARTMENT_CODE, "employmentInformation.primaryDepartmentCode" );
122
123 personCachePropertyNames.add( KIMPropertyConstants.Person.PRINCIPAL_ID );
124 personCachePropertyNames.add( KIMPropertyConstants.Person.PRINCIPAL_NAME );
125 personCachePropertyNames.add( KIMPropertyConstants.Person.ENTITY_ID );
126 personCachePropertyNames.add( KIMPropertyConstants.Person.FIRST_NAME );
127 personCachePropertyNames.add( KIMPropertyConstants.Person.LAST_NAME );
128 personCachePropertyNames.add( KIMPropertyConstants.Person.MIDDLE_NAME );
129 personCachePropertyNames.add( KIMPropertyConstants.Person.CAMPUS_CODE );
130 personCachePropertyNames.add( KIMPropertyConstants.Person.EMPLOYEE_ID );
131 personCachePropertyNames.add( KIMPropertyConstants.Person.PRIMARY_DEPARTMENT_CODE );
132 }
133
134
135
136
137
138 public Person getPerson(String principalId) {
139 if ( StringUtils.isBlank(principalId) ) {
140 return null;
141 }
142
143
144 final Principal principal = getIdentityService().getPrincipal( principalId );
145
146 if ( principal != null ) {
147 final EntityDefault entity = getIdentityService().getEntityDefault(principal.getEntityId());
148
149
150 if (entity != null ) {
151 return convertEntityToPerson( entity, principal );
152 }
153 }
154 return null;
155 }
156
157 protected PersonImpl convertEntityToPerson( EntityDefault entity, Principal principal ) {
158 try {
159
160 for ( String entityTypeCode : personEntityTypeCodes ) {
161 EntityTypeContactInfoDefault entType = entity.getEntityType( entityTypeCode );
162
163 if ( entType == null ) {
164 continue;
165 }
166
167
168 return new PersonImpl( principal, entity, entityTypeCode );
169 }
170 return null;
171 } catch ( Exception ex ) {
172
173 if ( ex instanceof RuntimeException ) {
174 throw (RuntimeException)ex;
175 }
176 throw new RuntimeException( "Problem building person object", ex );
177 }
178 }
179
180
181
182
183
184 public Person getPersonByPrincipalName(String principalName) {
185 if ( StringUtils.isBlank(principalName) ) {
186 return null;
187 }
188
189
190 final Principal principal = getIdentityService().getPrincipalByPrincipalName( principalName );
191
192 if ( principal != null ) {
193 final EntityDefault entity = getIdentityService().getEntityDefault(principal.getEntityId());
194
195
196 if ( entity != null ) {
197 return convertEntityToPerson( entity, principal );
198 }
199 }
200 return null;
201 }
202
203 public Person getPersonByEmployeeId(String employeeId) {
204 if ( StringUtils.isBlank( employeeId ) ) {
205 return null;
206 }
207
208 final List<Person> people = findPeople( Collections.singletonMap(KIMPropertyConstants.Person.EMPLOYEE_ID, employeeId) );
209 if ( !people.isEmpty() ) {
210 return people.get(0);
211
212 }
213 return null;
214 }
215
216
217
218
219 public List<Person> findPeople(Map<String, String> criteria) {
220 return findPeople(criteria, true);
221 }
222
223
224
225
226 public List<Person> findPeople(Map<String, String> criteria, boolean unbounded) {
227 List<Person> people = null;
228
229 if ( criteria == null ) {
230 criteria = Collections.emptyMap();
231 }
232
233 criteria = new HashMap<String, String>( criteria );
234
235
236 String roleName = criteria.get( "lookupRoleName" );
237 String namespaceCode = criteria.get( "lookupRoleNamespaceCode" );
238 criteria.remove("lookupRoleName");
239 criteria.remove("lookupRoleNamespaceCode");
240 if ( StringUtils.isNotBlank(namespaceCode) && StringUtils.isNotBlank(roleName) ) {
241 Integer searchResultsLimit = org.kuali.rice.kns.lookup.LookupUtils.getSearchResultsLimit(PersonImpl.class);
242 int searchResultsLimitInt = Integer.MAX_VALUE;
243 if (searchResultsLimit != null) {
244 searchResultsLimitInt = searchResultsLimit.intValue();
245 }
246 if ( LOG.isDebugEnabled() ) {
247 LOG.debug("Performing Person search including role filter: " + namespaceCode + "/" + roleName );
248 }
249 if ( criteria.size() == 1 && criteria.containsKey(KIMPropertyConstants.Person.ACTIVE) ) {
250 if ( LOG.isDebugEnabled() ) {
251 LOG.debug( "Only active criteria specified, running role search first" );
252 }
253
254 Collection<String> principalIds = getRoleService().getRoleMemberPrincipalIds(namespaceCode, roleName, Collections.<String, String>emptyMap());
255 StringBuffer sb = new StringBuffer(principalIds.size()*15);
256 Iterator<String> pi = principalIds.iterator();
257 while ( pi.hasNext() ) {
258 sb.append( pi.next() );
259 if ( pi.hasNext() ) sb.append( '|' );
260 }
261
262 criteria.put( KIMPropertyConstants.Person.PRINCIPAL_ID, sb.toString() );
263 people = findPeopleInternal(criteria, false);
264 } else if ( !criteria.isEmpty() ) {
265 if ( LOG.isDebugEnabled() ) {
266 LOG.debug( "Person criteria also specified, running that search first" );
267 }
268
269 people = findPeopleInternal(criteria, true);
270
271
272 List<String> principalIds = peopleToPrincipalIds( people );
273
274 principalIds = getRoleService().getPrincipalIdSubListWithRole(principalIds, namespaceCode, roleName, Collections.<String, String>emptyMap());
275
276 if ( !unbounded && principalIds.size() > searchResultsLimitInt ) {
277 int actualResultSize = principalIds.size();
278
279 principalIds = new ArrayList<String>(principalIds).subList(0, searchResultsLimitInt);
280 people = getPeople(principalIds);
281 people = new CollectionIncomplete<Person>( people.subList(0, searchResultsLimitInt), new Long(actualResultSize) );
282 } else {
283 people = getPeople(principalIds);
284 }
285 } else {
286 if ( LOG.isDebugEnabled() ) {
287 LOG.debug( "No Person criteria specified - only using role service." );
288 }
289
290 Collection<String> principalIds = getRoleService().getRoleMemberPrincipalIds(namespaceCode, roleName, Collections.<String, String>emptyMap());
291 if ( !unbounded && principalIds.size() > searchResultsLimitInt ) {
292 int actualResultSize = principalIds.size();
293
294 principalIds = new ArrayList<String>(principalIds).subList(0, searchResultsLimitInt);
295 people = getPeople(principalIds);
296 people = new CollectionIncomplete<Person>( people.subList(0, searchResultsLimitInt), new Long(actualResultSize) );
297 } else {
298 people = getPeople(principalIds);
299 }
300 }
301 } else {
302 if ( LOG.isDebugEnabled() ) {
303 LOG.debug( "No Role criteria specified, running person lookup as normal." );
304 }
305 people = findPeopleInternal(criteria, unbounded);
306 }
307
308
309
310
311
312 Set<String> peopleNoDupsSet = new HashSet<String>();
313 List<Person> peopleNoDupsList = new ArrayList<Person>();
314
315 for (Iterator<Person> iter = people.iterator(); iter.hasNext(); ) {
316 Person person = iter.next();
317 if (peopleNoDupsSet.add(person.getEntityId() + person.getPrincipalId() + person.getPrincipalName())) {
318 peopleNoDupsList.add(person);
319 }
320 }
321
322 people.clear();
323 people.addAll(peopleNoDupsList);
324
325 return people;
326 }
327
328 @SuppressWarnings("unchecked")
329 protected List<Person> findPeopleInternal(Map<String,String> criteria, boolean unbounded ) {
330
331
332
333 Map<String,String> entityCriteria = convertPersonPropertiesToEntityProperties( criteria );
334
335 Predicate predicate = PredicateUtils.convertMapToPredicate(entityCriteria);
336
337 QueryByCriteria.Builder queryBuilder = QueryByCriteria.Builder.create();
338 queryBuilder.setPredicates(predicate);
339
340 List<Person> people = new ArrayList<Person>();
341
342 EntityDefaultQueryResults qr = getIdentityService().findEntityDefaults( queryBuilder.build() );
343
344 for ( EntityDefault e : qr.getResults() ) {
345
346 for ( Principal p : e.getPrincipals() ) {
347 people.add( convertEntityToPerson( e, p ) );
348 }
349 }
350
351 return people;
352 }
353
354 public Map<String,String> convertPersonPropertiesToEntityProperties( Map<String,String> criteria ) {
355 if ( LOG.isDebugEnabled() ) {
356 LOG.debug( "convertPersonPropertiesToEntityProperties: " + criteria );
357 }
358 boolean nameCriteria = false;
359 boolean addressCriteria = false;
360 boolean externalIdentifierCriteria = false;
361 boolean affiliationCriteria = false;
362 boolean affiliationDefaultOnlyCriteria = false;
363 boolean phoneCriteria = false;
364 boolean emailCriteria = false;
365 boolean employeeIdCriteria = false;
366
367 HashMap<String,String> newCriteria = new HashMap<String,String>();
368 newCriteria.putAll( baseLookupCriteria );
369
370 newCriteria.put( "entityTypeContactInfos.entityTypeCode", personEntityTypeLookupCriteria );
371
372 if ( criteria != null ) {
373 for ( String key : criteria.keySet() ) {
374
375
376 if(key.equals(KIMPropertyConstants.Person.ACTIVE)) {
377 newCriteria.put(KIMPropertyConstants.Person.ACTIVE, criteria.get(KIMPropertyConstants.Person.ACTIVE));
378 }
379
380
381 if ( StringUtils.isEmpty( criteria.get(key) ) ) {
382 continue;
383 }
384
385
386 if ( key.equals( KIMPropertyConstants.Person.EXTERNAL_ID ) && StringUtils.isNotBlank(criteria.get(key)) ) {
387
388 if ( criteria.containsKey( KIMPropertyConstants.Person.EXTERNAL_IDENTIFIER_TYPE_CODE ) ) {
389 String extIdTypeCode = criteria.get(KIMPropertyConstants.Person.EXTERNAL_IDENTIFIER_TYPE_CODE);
390 if ( StringUtils.isNotBlank(extIdTypeCode) ) {
391
392 EntityExternalIdentifierType extIdType = getIdentityService().getExternalIdentifierType(extIdTypeCode);
393
394 if ( extIdType != null && extIdType.isEncryptionRequired() ) {
395 try {
396 criteria.put(key,
397 CoreApiServiceLocator.getEncryptionService().encrypt(criteria.get(key))
398 );
399 } catch (GeneralSecurityException ex) {
400 LOG.error("Unable to encrypt value for external ID search of type " + extIdTypeCode, ex );
401 }
402 }
403 }
404 }
405 }
406
407
408 String entityProperty = criteriaConversion.get( key );
409 if ( entityProperty != null ) {
410 newCriteria.put( entityProperty, criteria.get( key ) );
411 } else {
412 entityProperty = key;
413
414 newCriteria.put( key, criteria.get( key ) );
415 }
416
417 if ( isNameEntityCriteria( entityProperty ) ) {
418 nameCriteria = true;
419 }
420 if ( isExternalIdentifierEntityCriteria( entityProperty ) ) {
421 externalIdentifierCriteria = true;
422 }
423 if ( isAffiliationEntityCriteria( entityProperty ) ) {
424 affiliationCriteria = true;
425 }
426 if ( isAddressEntityCriteria( entityProperty ) ) {
427 addressCriteria = true;
428 }
429 if ( isPhoneEntityCriteria( entityProperty ) ) {
430 phoneCriteria = true;
431 }
432 if ( isEmailEntityCriteria( entityProperty ) ) {
433 emailCriteria = true;
434 }
435 if ( isEmployeeIdEntityCriteria( entityProperty ) ) {
436 employeeIdCriteria = true;
437 }
438
439
440 if ( key.equals( "campusCode" ) ) {
441 affiliationDefaultOnlyCriteria = true;
442 }
443 }
444 if ( nameCriteria ) {
445 newCriteria.put( ENTITY_NAME_PROPERTY_PREFIX + "active", "Y" );
446 newCriteria.put( ENTITY_NAME_PROPERTY_PREFIX + "defaultValue", "Y" );
447
448 }
449 if ( addressCriteria ) {
450 newCriteria.put( ENTITY_ADDRESS_PROPERTY_PREFIX + "active", "Y" );
451 newCriteria.put( ENTITY_ADDRESS_PROPERTY_PREFIX + "defaultValue", "Y" );
452 }
453 if ( phoneCriteria ) {
454 newCriteria.put( ENTITY_PHONE_PROPERTY_PREFIX + "active", "Y" );
455 newCriteria.put( ENTITY_PHONE_PROPERTY_PREFIX + "defaultValue", "Y" );
456 }
457 if ( emailCriteria ) {
458 newCriteria.put( ENTITY_EMAIL_PROPERTY_PREFIX + "active", "Y" );
459 newCriteria.put( ENTITY_EMAIL_PROPERTY_PREFIX + "defaultValue", "Y" );
460 }
461 if ( employeeIdCriteria ) {
462 newCriteria.put( ENTITY_EMPLOYEE_ID_PROPERTY_PREFIX + "active", "Y" );
463 newCriteria.put( ENTITY_EMPLOYEE_ID_PROPERTY_PREFIX + "primary", "Y" );
464 }
465 if ( affiliationCriteria ) {
466 newCriteria.put( ENTITY_AFFILIATION_PROPERTY_PREFIX + "active", "Y" );
467 }
468 if ( affiliationDefaultOnlyCriteria ) {
469 newCriteria.put( ENTITY_AFFILIATION_PROPERTY_PREFIX + "defaultValue", "Y" );
470 }
471 }
472
473 if ( LOG.isDebugEnabled() ) {
474 LOG.debug( "Converted: " + newCriteria );
475 }
476 return newCriteria;
477 }
478
479 protected boolean isNameEntityCriteria( String propertyName ) {
480 return propertyName.startsWith( ENTITY_NAME_PROPERTY_PREFIX );
481 }
482 protected boolean isAddressEntityCriteria( String propertyName ) {
483 return propertyName.startsWith( ENTITY_ADDRESS_PROPERTY_PREFIX );
484 }
485 protected boolean isPhoneEntityCriteria( String propertyName ) {
486 return propertyName.startsWith( ENTITY_PHONE_PROPERTY_PREFIX );
487 }
488 protected boolean isEmailEntityCriteria( String propertyName ) {
489 return propertyName.startsWith( ENTITY_EMAIL_PROPERTY_PREFIX );
490 }
491 protected boolean isEmployeeIdEntityCriteria( String propertyName ) {
492 return propertyName.startsWith( ENTITY_EMPLOYEE_ID_PROPERTY_PREFIX );
493 }
494 protected boolean isAffiliationEntityCriteria( String propertyName ) {
495 return propertyName.startsWith( ENTITY_AFFILIATION_PROPERTY_PREFIX );
496 }
497 protected boolean isExternalIdentifierEntityCriteria( String propertyName ) {
498 return propertyName.startsWith( ENTITY_EXT_ID_PROPERTY_PREFIX );
499 }
500
501
502
503
504
505
506 public List<String> getPersonEntityTypeCodes() {
507 return this.personEntityTypeCodes;
508 }
509
510 public void setPersonEntityTypeCodes(List<String> personEntityTypeCodes) {
511 this.personEntityTypeCodes = personEntityTypeCodes;
512 personEntityTypeLookupCriteria = null;
513 for ( String entityTypeCode : personEntityTypeCodes ) {
514 if ( personEntityTypeLookupCriteria == null ) {
515 personEntityTypeLookupCriteria = entityTypeCode;
516 } else {
517 personEntityTypeLookupCriteria = personEntityTypeLookupCriteria + "|" + entityTypeCode;
518 }
519 }
520 }
521
522
523 protected List<Person> getPeople( Collection<String> principalIds ) {
524 List<Person> people = new ArrayList<Person>( principalIds.size() );
525 for ( String principalId : principalIds ) {
526 people.add( getPerson(principalId) );
527 }
528 return people;
529 }
530
531 protected List<String> peopleToPrincipalIds( List<Person> people ) {
532 List<String> principalIds = new ArrayList<String>();
533
534 for ( Person person : people ) {
535 principalIds.add( person.getPrincipalId() );
536 }
537
538 return principalIds;
539 }
540
541
542
543
544 public List<Person> getPersonByExternalIdentifier(String externalIdentifierTypeCode, String externalId) {
545 if (StringUtils.isBlank( externalIdentifierTypeCode ) || StringUtils.isBlank( externalId ) ) {
546 return null;
547 }
548 Map<String,String> criteria = new HashMap<String,String>( 2 );
549 criteria.put( KIMPropertyConstants.Person.EXTERNAL_IDENTIFIER_TYPE_CODE, externalIdentifierTypeCode );
550 criteria.put( KIMPropertyConstants.Person.EXTERNAL_ID, externalId );
551 return findPeople( criteria );
552 }
553
554
555
556
557 public Person updatePersonIfNecessary(String sourcePrincipalId, Person currentPerson ) {
558 if (currentPerson == null
559 || !StringUtils.equals(sourcePrincipalId, currentPerson.getPrincipalId() )
560 || currentPerson.getEntityId() == null ) {
561 Person person = getPerson( sourcePrincipalId );
562
563
564 if ( person == null ) {
565 if ( currentPerson != null && currentPerson.getEntityId() == null ) {
566 return currentPerson;
567 }
568 }
569
570 if ( person == null && currentPerson == null ) {
571 try {
572 return new PersonImpl();
573 } catch ( Exception ex ) {
574 LOG.error( "unable to instantiate an object of type: " + getPersonImplementationClass() + " - returning null", ex );
575 return null;
576 }
577 }
578 return person;
579 }
580
581 return currentPerson;
582 }
583
584
585
586
587
588 private Map<String,String> getNonPersonSearchCriteria( BusinessObject bo, Map<String,String> fieldValues) {
589 Map<String,String> nonUniversalUserSearchCriteria = new HashMap<String,String>();
590 for ( String propertyName : fieldValues.keySet() ) {
591 if (!isPersonProperty(bo, propertyName)) {
592 nonUniversalUserSearchCriteria.put(propertyName, fieldValues.get(propertyName));
593 }
594 }
595 return nonUniversalUserSearchCriteria;
596 }
597
598
599 private boolean isPersonProperty(BusinessObject bo, String propertyName) {
600 try {
601 if ( ObjectUtils.isNestedAttribute( propertyName )
602 && !StringUtils.contains(propertyName, "add.") ) {
603 Class<?> type = PropertyUtils.getPropertyType(bo, ObjectUtils.getNestedAttributePrefix( propertyName ));
604
605 if ( type != null ) {
606 return Person.class.isAssignableFrom(type);
607 }
608 LOG.warn( "Unable to determine type of nested property: " + bo.getClass().getName() + " / " + propertyName );
609 }
610 } catch (Exception ex) {
611 if ( LOG.isDebugEnabled() ) {
612 LOG.debug("Unable to determine if property on " + bo.getClass().getName() + " to a person object: " + propertyName, ex );
613 }
614 }
615 return false;
616 }
617
618
619
620
621 public boolean hasPersonProperty(Class<? extends Person> businessObjectClass, Map<String,String> fieldValues) {
622 if ( businessObjectClass == null || fieldValues == null ) {
623 return false;
624 }
625 try {
626 BusinessObject bo = businessObjectClass.newInstance();
627 for ( String propertyName : fieldValues.keySet() ) {
628 if (isPersonProperty(bo, propertyName)) {
629 return true;
630 }
631 }
632 } catch (Exception ex) {
633 if ( LOG.isDebugEnabled() ) {
634 LOG.debug( "Error instantiating business object class passed into hasPersonProperty", ex );
635 }
636
637 }
638 return false;
639 }
640
641
642
643
644 @SuppressWarnings("unchecked")
645 public Map<String,String> resolvePrincipalNamesToPrincipalIds(BusinessObject businessObject, Map<String,String> fieldValues) {
646 if ( fieldValues == null ) {
647 return null;
648 }
649 if ( businessObject == null ) {
650 return fieldValues;
651 }
652 StringBuffer resolvedPrincipalIdPropertyName = new StringBuffer();
653
654
655 Map<String,String> processedFieldValues = getNonPersonSearchCriteria(businessObject, fieldValues);
656 for ( String propertyName : fieldValues.keySet() ) {
657 if ( !StringUtils.isBlank(fieldValues.get(propertyName))
658 && isPersonProperty(businessObject, propertyName)
659 ) {
660
661 String personPropertyName = ObjectUtils.getNestedAttributePrimitive( propertyName );
662
663 if ( StringUtils.equals( KIMPropertyConstants.Person.PRINCIPAL_NAME, personPropertyName) ) {
664 Class targetBusinessObjectClass = null;
665 BusinessObject targetBusinessObject = null;
666 resolvedPrincipalIdPropertyName.setLength( 0 );
667
668
669 String personReferenceObjectPropertyName = ObjectUtils.getNestedAttributePrefix( propertyName );
670
671
672 if ( ObjectUtils.isNestedAttribute( personReferenceObjectPropertyName ) ) {
673 String targetBusinessObjectPropertyName = ObjectUtils.getNestedAttributePrefix( personReferenceObjectPropertyName );
674 targetBusinessObject = (BusinessObject)ObjectUtils.getPropertyValue( businessObject, targetBusinessObjectPropertyName );
675 if (targetBusinessObject != null) {
676 targetBusinessObjectClass = targetBusinessObject.getClass();
677 resolvedPrincipalIdPropertyName.append(targetBusinessObjectPropertyName).append(".");
678 } else {
679 LOG.error("Could not find target property '"+propertyName+"' in class "+businessObject.getClass().getName()+". Property value was null.");
680 }
681 } else {
682 targetBusinessObjectClass = businessObject.getClass();
683 targetBusinessObject = businessObject;
684 }
685
686 if (targetBusinessObjectClass != null) {
687
688
689
690 String propName = ObjectUtils.getNestedAttributePrimitive( personReferenceObjectPropertyName );
691 DataObjectRelationship rel = getBusinessObjectMetaDataService().getBusinessObjectRelationship( targetBusinessObject, propName );
692 if ( rel != null ) {
693 String sourcePrimitivePropertyName = rel.getParentAttributeForChildAttribute(KIMPropertyConstants.Person.PRINCIPAL_ID);
694 resolvedPrincipalIdPropertyName.append(sourcePrimitivePropertyName);
695
696 String principalName = fieldValues.get( propertyName );
697 Principal principal = getIdentityService().getPrincipalByPrincipalName( principalName );
698 if (principal != null ) {
699 processedFieldValues.put(resolvedPrincipalIdPropertyName.toString(), principal.getPrincipalId());
700 } else {
701 processedFieldValues.put(resolvedPrincipalIdPropertyName.toString(), null);
702 try {
703
704
705
706
707 ObjectUtils.setObjectProperty(targetBusinessObject, resolvedPrincipalIdPropertyName.toString(), null );
708 ObjectUtils.setObjectProperty(targetBusinessObject, propName, null );
709 ObjectUtils.setObjectProperty(targetBusinessObject, propName + ".principalName", principalName );
710 } catch ( Exception ex ) {
711 LOG.error( "Unable to blank out the person object after finding that the person with the given principalName does not exist.", ex );
712 }
713 }
714 } else {
715 LOG.error( "Missing relationship for " + propName + " on " + targetBusinessObjectClass.getName() );
716 }
717 } else {
718 processedFieldValues.put(resolvedPrincipalIdPropertyName.toString(), null);
719 }
720 }
721
722
723
724 } else if (propertyName.endsWith("." + KIMPropertyConstants.Person.PRINCIPAL_NAME)){
725
726 String principalName = fieldValues.get(propertyName);
727 if ( StringUtils.isNotEmpty( principalName ) ) {
728 String containerPropertyName = propertyName;
729 if (containerPropertyName.startsWith(KRADConstants.MAINTENANCE_ADD_PREFIX)) {
730 containerPropertyName = StringUtils.substringAfter( propertyName, KRADConstants.MAINTENANCE_ADD_PREFIX );
731 }
732
733
734
735 if ( ObjectUtils.isNestedAttribute( containerPropertyName ) ) {
736
737 String collectionName = StringUtils.substringBefore( containerPropertyName, "." );
738
739
740
741 Class<? extends BusinessObject> collectionBusinessObjectClass = getMaintenanceDocumentDictionaryService()
742 .getCollectionBusinessObjectClass(
743 getMaintenanceDocumentDictionaryService()
744 .getDocumentTypeName(businessObject.getClass()), collectionName);
745 if (collectionBusinessObjectClass != null) {
746
747
748 List<DataObjectRelationship> relationships =
749 getBusinessObjectMetaDataService().getBusinessObjectRelationships( collectionBusinessObjectClass );
750
751
752 for ( DataObjectRelationship rel : relationships ) {
753 String parentAttribute = rel.getParentAttributeForChildAttribute( KIMPropertyConstants.Person.PRINCIPAL_ID );
754 if ( parentAttribute == null ) {
755 continue;
756 }
757
758 processedFieldValues.remove( propertyName );
759 String fieldPrefix = StringUtils.substringBeforeLast( StringUtils.substringBeforeLast( propertyName, "." + KIMPropertyConstants.Person.PRINCIPAL_NAME ), "." );
760 String relatedPrincipalIdPropertyName = fieldPrefix + "." + parentAttribute;
761
762 if(EXTENSION.equals(StringUtils.substringAfterLast(fieldPrefix, ".")) && EXTENSION.equals(StringUtils.substringBefore(parentAttribute, ".")))
763 {
764 relatedPrincipalIdPropertyName = fieldPrefix + "." + StringUtils.substringAfter(parentAttribute, ".");
765 }
766 String currRelatedPersonPrincipalId = processedFieldValues.get(relatedPrincipalIdPropertyName);
767 if ( StringUtils.isBlank( currRelatedPersonPrincipalId ) ) {
768 Principal principal = getIdentityService().getPrincipalByPrincipalName( principalName );
769 if ( principal != null ) {
770 processedFieldValues.put(relatedPrincipalIdPropertyName, principal.getPrincipalId());
771 } else {
772 processedFieldValues.put(relatedPrincipalIdPropertyName, null);
773 }
774 }
775 }
776 } else {
777 if ( LOG.isDebugEnabled() ) {
778 LOG.debug( "Unable to determine class for collection referenced as part of property: " + containerPropertyName + " on " + businessObject.getClass().getName() );
779 }
780 }
781 } else {
782 if ( LOG.isDebugEnabled() ) {
783 LOG.debug( "Non-nested property ending with 'principalName': " + containerPropertyName + " on " + businessObject.getClass().getName() );
784 }
785 }
786 }
787 }
788 }
789 return processedFieldValues;
790 }
791
792
793
794 protected IdentityService getIdentityService() {
795 if ( identityService == null ) {
796 identityService = KimApiServiceLocator.getIdentityService();
797 }
798 return identityService;
799 }
800
801 protected RoleService getRoleService() {
802 if ( roleService == null ) {
803 roleService = KimApiServiceLocator.getRoleService();
804 }
805 return roleService;
806 }
807
808
809 public Class<? extends Person> getPersonImplementationClass() {
810 return PersonImpl.class;
811 }
812
813 protected BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
814 if ( businessObjectMetaDataService == null ) {
815 businessObjectMetaDataService = KNSServiceLocator.getBusinessObjectMetaDataService();
816 }
817 return businessObjectMetaDataService;
818 }
819
820 protected MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
821 if ( maintenanceDocumentDictionaryService == null ) {
822 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
823 }
824 return maintenanceDocumentDictionaryService;
825 }
826 }