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