1 package org.kuali.rice.krad.service.impl;
2
3 import org.apache.commons.lang.StringUtils;
4 import org.apache.commons.lang.reflect.FieldUtils;
5 import org.eclipse.persistence.indirection.ValueHolder;
6 import org.kuali.rice.core.api.config.property.ConfigurationService;
7 import org.kuali.rice.core.api.criteria.QueryByCriteria;
8 import org.kuali.rice.core.api.datetime.DateTimeService;
9 import org.kuali.rice.core.api.exception.RiceRuntimeException;
10 import org.kuali.rice.core.api.mo.common.GloballyUnique;
11 import org.kuali.rice.core.api.mo.common.Versioned;
12 import org.kuali.rice.core.api.search.SearchOperator;
13 import org.kuali.rice.core.api.uif.RemotableQuickFinder;
14 import org.kuali.rice.core.api.util.RiceKeyConstants;
15 import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbCharBooleanConversion;
16 import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
17 import org.kuali.rice.krad.bo.*;
18 import org.kuali.rice.krad.dao.DocumentDao;
19 import org.kuali.rice.krad.dao.LookupDao;
20 import org.kuali.rice.krad.dao.MaintenanceDocumentDao;
21 import org.kuali.rice.krad.data.DataObjectService;
22 import org.kuali.rice.krad.datadictionary.*;
23 import org.kuali.rice.krad.document.Document;
24 import org.kuali.rice.krad.exception.ValidationException;
25 import org.kuali.rice.krad.lookup.LookupUtils;
26 import org.kuali.rice.krad.service.*;
27 import org.kuali.rice.krad.uif.UifPropertyPaths;
28 import org.kuali.rice.krad.uif.service.ViewDictionaryService;
29 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
30 import org.kuali.rice.krad.util.*;
31 import org.springframework.beans.PropertyAccessorUtils;
32 import org.springframework.beans.factory.annotation.Required;
33
34 import java.lang.reflect.Field;
35 import java.lang.reflect.InvocationTargetException;
36 import java.util.*;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.concurrent.ConcurrentMap;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41
42
43
44
45
46
47
48
49
50 @Deprecated
51 public class KNSLegacyDataAdapterImpl implements LegacyDataAdapter {
52 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(
53 KNSLegacyDataAdapterImpl.class);
54
55 private static final Pattern VALUE_HOLDER_FIELD_PATTERN = Pattern.compile("^_persistence_(.*)_vh$");
56
57 private final ConcurrentMap<Class<?>, List<ValueHolderFieldPair>> valueHolderFieldCache =
58 new ConcurrentHashMap<Class<?>, List<ValueHolderFieldPair>>(8, 0.9f, 1);
59
60 private BusinessObjectService businessObjectService;
61 private PersistenceService persistenceService;
62 private LookupDao lookupDao;
63 private LookupCriteriaGenerator lookupCriteriaGenerator;
64 private DateTimeService dateTimeService;
65 private DatabasePlatform databasePlatform;
66
67 private DocumentDao documentDao;
68 private MaintenanceDocumentDao maintenanceDocumentDaoOjb;
69
70 private PersistenceStructureService persistenceStructureService;
71 private DataObjectMetaDataService dataObjectMetaDataService;
72 private ConfigurationService kualiConfigurationService;
73 private KualiModuleService kualiModuleService;
74 private DataDictionaryService dataDictionaryService;
75 private DataObjectService dataObjectService;
76 private ViewDictionaryService viewDictionaryService;
77
78 @Override
79 public <T> T save(T dataObject) {
80 if (dataObject instanceof Collection) {
81 Collection<Object> newList = new ArrayList<Object>(((Collection) dataObject).size());
82 for (Object obj : (Collection<?>) dataObject) {
83 newList.add(save(obj));
84 }
85 return (T) newList;
86 } else {
87 return (T) businessObjectService.save((PersistableBusinessObject) dataObject);
88 }
89 }
90
91 @Override
92 public <T> T linkAndSave(T dataObject) {
93 return (T) businessObjectService.linkAndSave((PersistableBusinessObject) dataObject);
94 }
95
96 @Override
97 public <T> T saveDocument(T document) {
98 return (T) documentDao.save((Document) document);
99 }
100
101 @Override
102 public <T> T findByPrimaryKey(Class<T> clazz, Map<String, ?> primaryKeys) {
103 return (T) businessObjectService.findByPrimaryKey(clazz, primaryKeys);
104 }
105
106 @Override
107 public <T> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey) {
108 return (T) businessObjectService.findBySinglePrimaryKey(clazz, primaryKey);
109 }
110
111 @Override
112 public void delete(Object dataObject) {
113 if (dataObject instanceof Collection) {
114 for (Object dobj : (Collection) dataObject) {
115 delete(dobj);
116 }
117 } else {
118 businessObjectService.delete(dataObject);
119 }
120 }
121
122 @Override
123 public void deleteMatching(Class<?> type, Map<String, ?> fieldValues) {
124 businessObjectService.deleteMatching(type, fieldValues);
125 }
126
127 @Override
128 public <T> T retrieve(T dataObject) {
129 return (T) businessObjectService.retrieve(dataObject);
130 }
131
132 @Override
133 public <T> Collection<T> findAll(Class<T> clazz) {
134
135 return findMatching(clazz, Collections.<String, Object>emptyMap());
136 }
137
138 @Override
139 public <T> Collection<T> findMatching(Class<T> clazz, Map<String, ?> fieldValues) {
140 return (Collection<T>) businessObjectService.findMatching(clazz, fieldValues);
141 }
142
143 @Override
144 public <T> Collection<T> findMatchingOrderBy(Class<T> clazz, Map<String, ?> fieldValues, String sortField,
145 boolean sortAscending) {
146 return (Collection<T>) businessObjectService.findMatchingOrderBy(clazz, fieldValues,
147 sortField, sortAscending);
148 }
149
150 @Override
151 public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject) {
152 return persistenceService.getPrimaryKeyFieldValues(dataObject);
153 }
154
155 @Override
156 public void retrieveNonKeyFields(Object persistableObject) {
157 persistenceService.retrieveNonKeyFields(persistableObject);
158 synchronizeEclipseLinkWeavings(persistableObject);
159 }
160
161 @Override
162 public void retrieveReferenceObject(Object persistableObject, String referenceObjectName) {
163 persistenceService.retrieveReferenceObject(persistableObject, referenceObjectName);
164 synchronizeEclipseLinkWeavings(persistableObject, referenceObjectName);
165 }
166
167
168
169
170 protected void synchronizeEclipseLinkWeavings(Object persistableObject, String propertyName) {
171 if (LegacyUtils.isKradDataManaged(persistableObject.getClass())) {
172 List<ValueHolderFieldPair> fieldPairs = loadValueHolderFieldPairs(persistableObject.getClass());
173 for (ValueHolderFieldPair fieldPair : fieldPairs) {
174 if (fieldPair.field.getName().equals(propertyName)) {
175 fieldPair.synchronizeValueHolder(persistableObject);
176 }
177 }
178 }
179 }
180
181
182
183
184 protected void synchronizeEclipseLinkWeavings(Object persistableObject) {
185 if (LegacyUtils.isKradDataManaged(persistableObject.getClass())) {
186 List<ValueHolderFieldPair> fieldPairs = loadValueHolderFieldPairs(persistableObject.getClass());
187 for (ValueHolderFieldPair fieldPair : fieldPairs) {
188 fieldPair.synchronizeValueHolder(persistableObject);
189 }
190 }
191 }
192
193
194
195
196 private List<ValueHolderFieldPair> loadValueHolderFieldPairs(Class<?> type) {
197 if (valueHolderFieldCache.get(type) == null) {
198 List<ValueHolderFieldPair> pairs = new ArrayList<ValueHolderFieldPair>();
199 searchValueHolderFieldPairs(type, pairs);
200 valueHolderFieldCache.putIfAbsent(type, pairs);
201 }
202 return valueHolderFieldCache.get(type);
203 }
204
205
206
207
208 private void searchValueHolderFieldPairs(Class<?> type, List<ValueHolderFieldPair> pairs) {
209 if (type.equals(Object.class)) {
210 return;
211 }
212 for (Field valueHolderField : type.getDeclaredFields()) {
213 Matcher matcher = VALUE_HOLDER_FIELD_PATTERN.matcher(valueHolderField.getName());
214 if (matcher.matches()) {
215 valueHolderField.setAccessible(true);
216 String fieldName = matcher.group(1);
217 Field valueField = FieldUtils.getDeclaredField(type, fieldName, true);
218 if (valueField != null) {
219 pairs.add(new ValueHolderFieldPair(valueField, valueHolderField));
220 }
221 }
222 }
223 searchValueHolderFieldPairs(type.getSuperclass(), pairs);
224 }
225
226 @Override
227 public void refreshAllNonUpdatingReferences(Object persistableObject) {
228 persistenceService.refreshAllNonUpdatingReferences((PersistableBusinessObject) persistableObject);
229 synchronizeEclipseLinkWeavings(persistableObject);
230 }
231
232 @Override
233 public boolean isProxied(Object object) {
234 if (object == null || (!(object instanceof BusinessObject) && !(object instanceof PersistableBusinessObjectBaseAdapter))) {
235 return false;
236 }
237 return persistenceService.isProxied(object);
238 }
239
240 @Override
241 public Object resolveProxy(Object o) {
242 return persistenceService.resolveProxy(o);
243 }
244
245
246
247 @Override
248 public <T> Collection<T> findCollectionBySearchHelper(Class<T> dataObjectClass, Map<String, String> formProperties,
249 boolean unbounded, boolean allPrimaryKeyValuesPresentAndNotWildcard, Integer searchResultsLimit) {
250 return lookupDao.findCollectionBySearchHelper(dataObjectClass, formProperties, unbounded,
251 allPrimaryKeyValuesPresentAndNotWildcard, searchResultsLimit);
252 }
253
254
255 @Override
256 public <T> Collection<T> findCollectionBySearchHelper(Class<T> dataObjectClass, Map<String, String> formProperties,
257 List<String> wildcardAsLiteralPropertyNames, boolean unbounded,
258 boolean allPrimaryKeyValuesPresentAndNotWildcard, Integer searchResultsLimit) {
259 return lookupDao.findCollectionBySearchHelper(dataObjectClass, formProperties, unbounded,
260 allPrimaryKeyValuesPresentAndNotWildcard, searchResultsLimit);
261 }
262
263
264
265
266
267
268
269
270
271
272 protected <T> Collection<T> performDataObjectServiceLookup(Class<T> dataObjectClass,
273 Map<String, String> formProperties, boolean unbounded, boolean allPrimaryKeyValuesPresentAndNotWildcard,
274 Integer searchResultsLimit) {
275 if (!unbounded && searchResultsLimit == null) {
276
277
278 searchResultsLimit = org.kuali.rice.kns.lookup.LookupUtils.getSearchResultsLimit(dataObjectClass);
279 }
280 QueryByCriteria.Builder query = lookupCriteriaGenerator.generateCriteria(dataObjectClass, formProperties,
281 allPrimaryKeyValuesPresentAndNotWildcard);
282 if (!unbounded && searchResultsLimit != null) {
283 query.setMaxResults(searchResultsLimit);
284 }
285
286 Collection<T> results = dataObjectService.findMatching(dataObjectClass, query.build()).getResults();
287 return filterCurrentDataObjects(dataObjectClass, results, formProperties);
288 }
289
290 protected <T> Collection<T> filterCurrentDataObjects(Class<T> dataObjectClass, Collection<T> unfiltered,
291 Map<String, String> formProps) {
292 if (InactivatableFromTo.class.isAssignableFrom(dataObjectClass)) {
293 Boolean currentSpecifier = lookupCriteriaCurrentSpecifier(formProps);
294 if (currentSpecifier != null) {
295 List<InactivatableFromTo> onlyCurrent =
296 KRADServiceLocator.getInactivateableFromToService().filterOutNonCurrent(new ArrayList(
297 unfiltered), new Date(LookupUtils.getActiveDateTimestampForCriteria(formProps)
298 .getTime()));
299 if (currentSpecifier) {
300 return (Collection<T>) onlyCurrent;
301 } else {
302 unfiltered.removeAll(onlyCurrent);
303 return unfiltered;
304 }
305 }
306 }
307 return unfiltered;
308 }
309
310 protected Boolean lookupCriteriaCurrentSpecifier(Map<String, String> formProps) {
311 String value = formProps.get(KRADPropertyConstants.CURRENT);
312 if (StringUtils.isNotBlank(value)) {
313
314 String currentBooleanStr = (String) new OjbCharBooleanConversion().javaToSql(value);
315 if (OjbCharBooleanConversion.DATABASE_BOOLEAN_TRUE_STRING_REPRESENTATION.equals(currentBooleanStr)) {
316 return Boolean.TRUE;
317 } else if (OjbCharBooleanConversion.DATABASE_BOOLEAN_FALSE_STRING_REPRESENTATION.equals(
318 currentBooleanStr)) {
319 return Boolean.FALSE;
320 }
321 }
322 return null;
323 }
324
325 @Override
326 public <T> T findObjectBySearch(Class<T> type, Map<String, String> formProps) {
327 return lookupDao.findObjectByMap(type, formProps);
328 }
329
330
331
332
333
334
335
336
337 @Override
338 public boolean allPrimaryKeyValuesPresentAndNotWildcard(Class<?> boClass, Map<String, String> formProps) {
339 List<String> pkFields = listPrimaryKeyFieldNames(boClass);
340 Iterator<String> pkIter = pkFields.iterator();
341 boolean returnVal = true;
342 while (returnVal && pkIter.hasNext()) {
343 String pkName = pkIter.next();
344 String pkValue = formProps.get(pkName);
345
346 if (StringUtils.isBlank(pkValue)) {
347 returnVal = false;
348 } else {
349 for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) {
350 if (pkValue.contains(op.op())) {
351 returnVal = false;
352 break;
353 }
354 }
355 }
356 }
357 return returnVal;
358 }
359
360 @SuppressWarnings("unchecked")
361 @Override
362 public List<String> listPrimaryKeyFieldNames(Class<?> type) {
363 List<String> keys = new ArrayList<String>();
364 if ( type == null ) {
365 return keys;
366 }
367 if (isPersistable(type)) {
368 keys = persistenceStructureService.listPrimaryKeyFieldNames(type);
369 } else {
370 ModuleService responsibleModuleService = kualiModuleService.getResponsibleModuleService(type);
371 if (responsibleModuleService != null && responsibleModuleService.isExternalizable(type)) {
372 keys = responsibleModuleService.listPrimaryKeyFieldNames(type);
373 } else {
374
375 DataObjectEntry dataObjectEntry = dataDictionaryService.getDataDictionary().getDataObjectEntry(type.getName());
376 if ( dataObjectEntry != null ) {
377 List<String> pks = dataObjectEntry.getPrimaryKeys();
378 if (pks != null ) {
379 keys = pks;
380 }
381 } else {
382 LOG.warn( "Unable to retrieve data object entry for non-persistable KNS-managed class: " + type.getName() );
383 }
384 }
385 }
386 return keys;
387 }
388
389
390
391
392
393
394
395
396
397
398
399
400
401 protected List<String> listPrimaryKeyFieldNamesConsultingAllServices(Class<?> type) {
402 return dataObjectMetaDataService.listPrimaryKeyFieldNames(type);
403 }
404
405 @Override
406 public Class<?> determineCollectionObjectType(Class<?> containingType, String collectionPropertyName) {
407 final Class<?> collectionObjectType;
408 if (isPersistable(containingType)) {
409 Map<String, Class> collectionClasses = new HashMap<String, Class>();
410 collectionClasses = persistenceStructureService.listCollectionObjectTypes(containingType);
411 collectionObjectType = collectionClasses.get(collectionPropertyName);
412 } else {
413 throw new RuntimeException(
414 "Can't determine the Class of Collection elements because persistenceStructureService.isPersistable("
415 + containingType.getName()
416 + ") returns false.");
417 }
418 return collectionObjectType;
419
420 }
421
422 @Override
423 public boolean hasReference(Class<?> boClass, String referenceName) {
424 return persistenceStructureService.hasReference(boClass, referenceName);
425 }
426
427 @Override
428 public boolean hasCollection(Class<?> boClass, String collectionName) {
429 return persistenceStructureService.hasCollection(boClass, collectionName);
430 }
431
432 @Override
433 public boolean isExtensionAttribute(Class<?> boClass, String attributePropertyName, Class<?> propertyType) {
434 return propertyType.equals(PersistableBusinessObjectExtension.class);
435 }
436
437 @Override
438 public Class<?> getExtensionAttributeClass(Class<?> boClass, String attributePropertyName) {
439 return persistenceStructureService.getBusinessObjectAttributeClass((Class<? extends PersistableBusinessObject>)boClass, attributePropertyName);
440 }
441
442
443 @Override
444 public Map<String, ?> getPrimaryKeyFieldValuesDOMDS(Object dataObject) {
445 return dataObjectMetaDataService.getPrimaryKeyFieldValues(dataObject);
446 }
447
448 @Override
449 public boolean equalsByPrimaryKeys(Object do1, Object do2) {
450 return dataObjectMetaDataService.equalsByPrimaryKeys(do1, do2);
451 }
452
453 @Override
454 public void materializeAllSubObjects(Object object) {
455 ObjectUtils.materializeAllSubObjects((PersistableBusinessObject) object);
456 }
457
458 @Override
459 public Class<?> getPropertyType(Object object, String propertyName) {
460 return ObjectUtils.getPropertyType(object, propertyName, persistenceStructureService);
461 }
462
463 @Override
464 public Object getExtension(
465 Class<?> businessObjectClass) throws InstantiationException, IllegalAccessException {
466 Class<? extends PersistableBusinessObjectExtension> extensionClass =
467 persistenceStructureService.getBusinessObjectAttributeClass((Class<? extends PersistableBusinessObject>) businessObjectClass, "extension");
468 if (extensionClass != null) {
469 return extensionClass.newInstance();
470 }
471 return null;
472 }
473
474 @Override
475 public void refreshReferenceObject(Object businessObject, String referenceObjectName) {
476 if (StringUtils.isNotBlank(referenceObjectName) && !StringUtils.equals(referenceObjectName, "extension")) {
477 if (persistenceStructureService.hasReference(businessObject.getClass(), referenceObjectName)
478 || persistenceStructureService.hasCollection(businessObject.getClass(), referenceObjectName)) {
479 retrieveReferenceObject(businessObject, referenceObjectName);
480 }
481 }
482 }
483
484 @Override
485 public boolean isLockable(Object object) {
486 return isPersistable(object.getClass());
487 }
488
489 @Override
490 public void verifyVersionNumber(Object dataObject) {
491 if (isPersistable(dataObject.getClass())) {
492 Object pbObject = businessObjectService.retrieve(dataObject);
493 if ( dataObject instanceof Versioned) {
494 Long pbObjectVerNbr = KRADUtils.isNull(pbObject) ? null : ((Versioned) pbObject).getVersionNumber();
495 Long newObjectVerNbr = ((Versioned) dataObject).getVersionNumber();
496 if (pbObjectVerNbr != null && !(pbObjectVerNbr.equals(newObjectVerNbr))) {
497 GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS,
498 RiceKeyConstants.ERROR_VERSION_MISMATCH);
499 throw new ValidationException(
500 "Version mismatch between the local business object and the database business object");
501 }
502 }
503 }
504 }
505
506 @Override
507 public RemotableQuickFinder.Builder createQuickFinder(Class<?> containingClass, String attributeName) {
508 return createQuickFinderLegacy(containingClass, attributeName);
509 }
510
511
512
513
514 protected RemotableQuickFinder.Builder createQuickFinderLegacy(Class<?> containingClass, String attributeName) {
515 Object sampleComponent;
516 try {
517 sampleComponent = containingClass.newInstance();
518 } catch (InstantiationException e) {
519 throw new RiceRuntimeException(e);
520 } catch (IllegalAccessException e) {
521 throw new RiceRuntimeException(e);
522 }
523
524 String lookupClassName = null;
525 Map<String, String> fieldConversions = new HashMap<String, String>();
526 Map<String, String> lookupParameters = new HashMap<String, String>();
527
528 org.kuali.rice.krad.bo.DataObjectRelationship relationship =
529 getDataObjectRelationship(sampleComponent, containingClass, attributeName, "",
530 true, true, false);
531 if (relationship != null) {
532 lookupClassName = relationship.getRelatedClass().getName();
533
534 for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
535 String fromField = entry.getValue();
536 String toField = entry.getKey();
537 fieldConversions.put(fromField, toField);
538 }
539
540 for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
541 String fromField = entry.getKey();
542 String toField = entry.getValue();
543
544 if (relationship.getUserVisibleIdentifierKey() == null || relationship.getUserVisibleIdentifierKey()
545 .equals(fromField)) {
546 lookupParameters.put(fromField, toField);
547 }
548 }
549 } else {
550
551 String titleAttribute = dataObjectMetaDataService.getTitleAttribute(containingClass);
552 if (StringUtils.equals(titleAttribute, attributeName)) {
553 lookupClassName = containingClass.getName();
554
555 List<String> pkAttributes = dataObjectMetaDataService.listPrimaryKeyFieldNames(containingClass);
556 for (String pkAttribute : pkAttributes) {
557 fieldConversions.put(pkAttribute, pkAttribute);
558 if (!StringUtils.equals(pkAttribute, attributeName)) {
559 lookupParameters.put(pkAttribute, pkAttribute);
560 }
561 }
562 }
563 }
564
565 if (StringUtils.isNotBlank(lookupClassName)) {
566 String baseUrl = kualiConfigurationService.getPropertyValueAsString(KRADConstants.KRAD_LOOKUP_URL_KEY);
567 RemotableQuickFinder.Builder builder = RemotableQuickFinder.Builder.create(baseUrl, lookupClassName);
568 builder.setLookupParameters(lookupParameters);
569 builder.setFieldConversions(fieldConversions);
570
571 return builder;
572 }
573
574 return null;
575 }
576
577
578 @Override
579 public boolean isReferenceUpdatable(Class<?> type, String referenceName) {
580 return persistenceStructureService.isReferenceUpdatable(type, referenceName);
581 }
582
583 @SuppressWarnings("rawtypes")
584 @Override
585 public Map<String, Class> listReferenceObjectFields(Class<?> type) {
586 return persistenceStructureService.listReferenceObjectFields(type);
587 }
588
589 @Override
590 public boolean isCollectionUpdatable(Class<?> type, String collectionName) {
591 return persistenceStructureService.isCollectionUpdatable(type, collectionName);
592 }
593
594 @Override
595 public Map<String, Class> listCollectionObjectTypes(Class<?> type) {
596 return persistenceStructureService.listCollectionObjectTypes(type);
597 }
598
599 @Override
600 public BusinessObject getReferenceIfExists(Object bo, String referenceName) {
601 if (!(bo instanceof BusinessObject)) {
602 throw new UnsupportedOperationException("getReferenceIfExists only supports BusinessObject in KNS");
603 }
604
605 return businessObjectService.getReferenceIfExists((BusinessObject) bo, referenceName);
606 }
607
608 @Override
609 public boolean allForeignKeyValuesPopulatedForReference(Object bo, String referenceName) {
610 if (!(bo instanceof PersistableBusinessObject)) {
611 throw new UnsupportedOperationException(
612 "getReferenceIfExists only supports PersistableBusinessObject in KNS");
613 }
614
615 return persistenceService.allForeignKeyValuesPopulatedForReference((PersistableBusinessObject) bo,
616 referenceName);
617 }
618
619
620
621
622
623
624
625
626 @Override
627 public RelationshipDefinition getDictionaryRelationship(Class<?> c, String attributeName) {
628 DataDictionaryEntry entryBase =
629 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(
630 c.getName());
631 if (entryBase == null) {
632 return null;
633 }
634
635 RelationshipDefinition relationship = null;
636
637 List<RelationshipDefinition> ddRelationships = entryBase.getRelationships();
638
639 int minKeys = Integer.MAX_VALUE;
640 for (RelationshipDefinition def : ddRelationships) {
641
642 if (def.getPrimitiveAttributes().size() == 1) {
643 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
644 if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
645 attributeName)) {
646 relationship = def;
647 minKeys = 1;
648 break;
649 }
650 }
651 } else if (def.getPrimitiveAttributes().size() < minKeys) {
652 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
653 if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
654 attributeName)) {
655 relationship = def;
656 minKeys = def.getPrimitiveAttributes().size();
657 break;
658 }
659 }
660 }
661 }
662
663
664 if (relationship == null) {
665 for (RelationshipDefinition def : ddRelationships) {
666 if (def.hasIdentifier()) {
667 if (def.getIdentifier().getSourceName().equals(attributeName)) {
668 relationship = def;
669 }
670 }
671 }
672 }
673
674 return relationship;
675 }
676
677
678
679
680 @Override
681 public String getTitleAttribute(Class<?> dataObjectClass) {
682 String titleAttribute = null;
683 DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
684 if (entry != null) {
685 titleAttribute = entry.getTitleAttribute();
686 }
687 return titleAttribute;
688 }
689
690
691
692
693
694
695
696 protected DataObjectEntry getDataObjectEntry(Class<?> dataObjectClass) {
697 if (dataObjectClass == null) {
698 throw new IllegalArgumentException("invalid (null) dataObjectClass");
699 }
700
701 DataObjectEntry entry = dataDictionaryService.getDataDictionary().getDataObjectEntry(dataObjectClass.getName());
702
703 return entry;
704 }
705
706
707
708
709 @Override
710 public boolean areNotesSupported(Class<?> dataObjectClass) {
711 boolean hasNotesSupport = false;
712
713 DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
714 if (entry != null) {
715 hasNotesSupport = entry.isBoNotesEnabled();
716 }
717
718 return hasNotesSupport;
719 }
720
721
722
723
724
725
726
727
728 public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject, boolean sortFieldNames) {
729 Map<String, Object> keyFieldValues = (Map<String, Object>) getPrimaryKeyFieldValues(dataObject);
730 if (sortFieldNames) {
731 Map<String, Object> sortedKeyFieldValues = new TreeMap<String, Object>();
732 sortedKeyFieldValues.putAll(keyFieldValues);
733 return sortedKeyFieldValues;
734 }
735 return keyFieldValues;
736 }
737
738
739
740
741 @Override
742 public String getDataObjectIdentifierString(Object dataObject) {
743 String identifierString = "";
744
745 if (dataObject == null) {
746 identifierString = "Null";
747 return identifierString;
748 }
749
750 Class<?> dataObjectClass = dataObject.getClass();
751
752 if ((PersistableBusinessObject.class.isAssignableFrom(
753 dataObjectClass)) || (!LegacyUtils.useLegacyForObject(dataObject) && GloballyUnique.class
754 .isAssignableFrom(dataObjectClass))) {
755 String objectId = ObjectPropertyUtils.getPropertyValue(dataObject, UifPropertyPaths.OBJECT_ID);
756 if (StringUtils.isBlank(objectId)) {
757 objectId = UUID.randomUUID().toString();
758 ObjectPropertyUtils.setPropertyValue(dataObject, UifPropertyPaths.OBJECT_ID, objectId);
759 }
760 }
761 return identifierString;
762 }
763
764 @Override
765 public Class<?> getInquiryObjectClassIfNotTitle(Object dataObject, String propertyName) {
766 Class<?> objectClass = ObjectUtils.materializeClassForProxiedObject(dataObject);
767 org.kuali.rice.krad.bo.DataObjectRelationship relationship =
768 dataObjectMetaDataService.getDataObjectRelationship(dataObject, objectClass, propertyName, "", true,
769 false, true);
770 if (relationship != null) {
771 return relationship.getRelatedClass();
772 }
773 return null;
774 }
775
776 @Override
777 public Map<String, String> getInquiryParameters(Object dataObject, List<String> keys, String propertyName) {
778 Map<String, String> inquiryParameters = new HashMap<String, String>();
779 Class<?> objectClass = ObjectUtils.materializeClassForProxiedObject(dataObject);
780 org.kuali.rice.krad.bo.DataObjectRelationship relationship =
781 dataObjectMetaDataService.getDataObjectRelationship(dataObject, objectClass, propertyName, "", true,
782 false, true);
783 for (String keyName : keys) {
784 String keyConversion = keyName;
785 if (relationship != null) {
786 keyConversion = relationship.getParentAttributeForChildAttribute(keyName);
787 } else if (PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName)) {
788 String nestedAttributePrefix = KRADUtils.getNestedAttributePrefix(propertyName);
789 keyConversion = nestedAttributePrefix + "." + keyName;
790 }
791 inquiryParameters.put(keyConversion, keyName);
792 }
793 return inquiryParameters;
794 }
795
796 @Override
797 public boolean hasLocalLookup(Class<?> dataObjectClass) {
798 return dataObjectMetaDataService.hasLocalLookup(dataObjectClass);
799 }
800
801 @Override
802 public boolean hasLocalInquiry(Class<?> dataObjectClass) {
803 return dataObjectMetaDataService.hasLocalInquiry(dataObjectClass);
804 }
805
806 @Override
807 public org.kuali.rice.krad.bo.DataObjectRelationship getDataObjectRelationship(Object dataObject,
808 Class<?> dataObjectClass, String attributeName, String attributePrefix, boolean keysOnly,
809 boolean supportsLookup, boolean supportsInquiry) {
810 RelationshipDefinition ddReference = getDictionaryRelationship(dataObjectClass, attributeName);
811 return dataObjectMetaDataService.getDataObjectRelationship(dataObject, dataObjectClass, attributeName,
812 attributePrefix, keysOnly, supportsLookup, supportsInquiry);
813
814 }
815
816
817
818 protected org.kuali.rice.krad.bo.DataObjectRelationship populateRelationshipFromDictionaryReference(Class<?> dataObjectClass,
819 RelationshipDefinition ddReference, String attributePrefix, boolean keysOnly) {
820 org.kuali.rice.krad.bo.DataObjectRelationship relationship = new org.kuali.rice.krad.bo.DataObjectRelationship(dataObjectClass,
821 ddReference.getObjectAttributeName(), ddReference.getTargetClass());
822
823 for (PrimitiveAttributeDefinition def : ddReference.getPrimitiveAttributes()) {
824 if (StringUtils.isNotBlank(attributePrefix)) {
825 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
826 def.getTargetName());
827 } else {
828 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
829 }
830 }
831
832 if (!keysOnly) {
833 for (SupportAttributeDefinition def : ddReference.getSupportAttributes()) {
834 if (StringUtils.isNotBlank(attributePrefix)) {
835 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
836 def.getTargetName());
837 if (def.isIdentifier()) {
838 relationship.setUserVisibleIdentifierKey(attributePrefix + "." + def.getSourceName());
839 }
840 } else {
841 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
842 if (def.isIdentifier()) {
843 relationship.setUserVisibleIdentifierKey(def.getSourceName());
844 }
845 }
846 }
847 }
848
849 return relationship;
850 }
851
852 @Override
853 public boolean isPersistable(Class<?> dataObjectClass) {
854 return persistenceStructureService.isPersistable(dataObjectClass);
855 }
856
857 @Override
858 public void setObjectPropertyDeep(Object bo, String propertyName, Class type,
859 Object propertyValue) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
860 ObjectUtils.setObjectPropertyDeep(bo,propertyName,type,propertyValue);
861 }
862
863 protected org.kuali.rice.krad.bo.DataObjectRelationship getRelationshipMetadata(Class<?> dataObjectClass,
864 String attributeName, String attributePrefix) {
865
866 RelationshipDefinition relationshipDefinition = getDictionaryRelationship(dataObjectClass, attributeName);
867 if (relationshipDefinition == null) {
868 return null;
869 }
870
871 org.kuali.rice.krad.bo.DataObjectRelationship dataObjectRelationship =
872 new org.kuali.rice.krad.bo.DataObjectRelationship(relationshipDefinition.getSourceClass(),
873 relationshipDefinition.getObjectAttributeName(), relationshipDefinition.getTargetClass());
874
875 if (!StringUtils.isEmpty(attributePrefix)) {
876 attributePrefix += ".";
877 }
878
879 List<PrimitiveAttributeDefinition> primitives = relationshipDefinition.getPrimitiveAttributes();
880 for (PrimitiveAttributeDefinition primitiveAttributeDefinition : primitives) {
881 dataObjectRelationship.getParentToChildReferences().put(
882 attributePrefix + primitiveAttributeDefinition.getSourceName(),
883 primitiveAttributeDefinition.getTargetName());
884 }
885
886 return dataObjectRelationship;
887 }
888
889 protected boolean classHasSupportedFeatures(Class relationshipClass, boolean supportsLookup,
890 boolean supportsInquiry) {
891 boolean hasSupportedFeatures = true;
892 if (supportsLookup && !getViewDictionaryService().isLookupable(relationshipClass)) {
893 hasSupportedFeatures = false;
894 }
895 if (supportsInquiry && !getViewDictionaryService().isInquirable(relationshipClass)) {
896 hasSupportedFeatures = false;
897 }
898
899 return hasSupportedFeatures;
900 }
901
902 @Override
903 public boolean isNull(Object object){
904 return ObjectUtils.isNull(object);
905 }
906
907 @Override
908 public void setObjectProperty(Object bo, String propertyName, Class propertyType,
909 Object propertyValue) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
910 ObjectUtils.setObjectProperty(bo,propertyName,propertyType,propertyValue);
911 }
912
913 @Override
914 public Class materializeClassForProxiedObject(Object object){
915 return ObjectUtils.materializeClassForProxiedObject(object);
916 }
917
918 @Override
919 public Object getNestedValue(Object bo, String fieldName){
920 return ObjectUtils.getNestedValue(bo,fieldName);
921 }
922
923 @Override
924 public Object createNewObjectFromClass(Class clazz){
925 return ObjectUtils.createNewObjectFromClass(clazz);
926 }
927
928 @Override
929 public ForeignKeyFieldsPopulationState getForeignKeyFieldsPopulationState(Object dataObject, String referenceName) {
930 return persistenceStructureService.getForeignKeyFieldsPopulationState(
931 (PersistableBusinessObject) dataObject, referenceName);
932 }
933
934 @Override
935 public Map<String, String> getForeignKeysForReference(Class<?> clazz, String attributeName) {
936 return persistenceStructureService.getForeignKeysForReference(clazz, attributeName);
937 }
938
939 @Override
940 public boolean hasPrimaryKeyFieldValues(Object dataObject) {
941 return persistenceStructureService.hasPrimaryKeyFieldValues(dataObject);
942 }
943
944 @Override
945 public <T extends Document> T findByDocumentHeaderId(Class<T> documentClass, String id) {
946 return documentDao.findByDocumentHeaderId(documentClass, id);
947 }
948
949 @Override
950 public <T extends Document> List<T> findByDocumentHeaderIds(Class<T> documentClass, List<String> ids) {
951 return documentDao.findByDocumentHeaderIds(documentClass, ids);
952 }
953
954
955 @Required
956 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
957 this.businessObjectService = businessObjectService;
958 }
959
960 @Required
961 public void setPersistenceService(PersistenceService persistenceService) {
962 this.persistenceService = persistenceService;
963 }
964
965 @Required
966 public void setLookupDao(LookupDao lookupDao) {
967 this.lookupDao = lookupDao;
968 }
969
970 @Required
971 public void setLookupCriteriaGenerator(LookupCriteriaGenerator lookupCriteriaGenerator) {
972 this.lookupCriteriaGenerator = lookupCriteriaGenerator;
973 }
974
975 @Required
976 public void setDateTimeService(DateTimeService dts) {
977 this.dateTimeService = dts;
978 }
979
980 @Required
981 public void setDatabasePlatform(DatabasePlatform databasePlatform) {
982 this.databasePlatform = databasePlatform;
983 }
984
985 @Required
986 public void setMaintenanceDocumentDaoOjb(MaintenanceDocumentDao maintenanceDocumentDaoOjb) {
987 this.maintenanceDocumentDaoOjb = maintenanceDocumentDaoOjb;
988 }
989
990
991
992
993
994
995 @Required
996 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
997 this.persistenceStructureService = persistenceStructureService;
998 }
999
1000 @Required
1001 public void setDataObjectMetaDataService(DataObjectMetaDataService dataObjectMetaDataService) {
1002 this.dataObjectMetaDataService = dataObjectMetaDataService;
1003 }
1004
1005 @Required
1006 public void setKualiConfigurationService(ConfigurationService kualiConfigurationService) {
1007 this.kualiConfigurationService = kualiConfigurationService;
1008 }
1009
1010 @Required
1011 public void setKualiModuleService(KualiModuleService kualiModuleService) {
1012 this.kualiModuleService = kualiModuleService;
1013 }
1014
1015 @Required
1016 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
1017 this.dataDictionaryService = dataDictionaryService;
1018 }
1019
1020 @Required
1021 public void setDocumentDao(DocumentDao documentDao) {
1022 this.documentDao = documentDao;
1023 }
1024
1025 public DataObjectService getDataObjectService() {
1026 return dataObjectService;
1027 }
1028
1029 public void setDataObjectService(DataObjectService dataObjectService) {
1030 this.dataObjectService = dataObjectService;
1031 }
1032
1033 public ViewDictionaryService getViewDictionaryService() {
1034 return viewDictionaryService;
1035 }
1036
1037 public void setViewDictionaryService(ViewDictionaryService viewDictionaryService) {
1038 this.viewDictionaryService = viewDictionaryService;
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 private static final class ValueHolderFieldPair {
1055
1056 final Field field;
1057 final Field valueHolderField;
1058
1059 ValueHolderFieldPair(Field field, Field valueHolderField) {
1060 this.field = field;
1061 this.valueHolderField = valueHolderField;
1062 }
1063
1064 void synchronizeValueHolder(Object object) {
1065 try {
1066 ValueHolder valueHolder = (ValueHolder)valueHolderField.get(object);
1067 if(valueHolder != null){
1068 Object value = field.get(object);
1069 valueHolder.setValue(value);
1070 }
1071 } catch (IllegalAccessException e) {
1072 throw new RuntimeException(e);
1073 }
1074 }
1075
1076 }
1077
1078 }
1079