View Javadoc

1   /*
2    * Copyright 2006-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.kuali.rice.krad.service.impl;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.config.property.ConfigurationService;
21  import org.kuali.rice.core.api.criteria.QueryByCriteria;
22  import org.kuali.rice.core.api.datetime.DateTimeService;
23  import org.kuali.rice.core.api.exception.RiceRuntimeException;
24  import org.kuali.rice.core.api.mo.common.GloballyUnique;
25  import org.kuali.rice.core.api.search.SearchOperator;
26  import org.kuali.rice.core.api.uif.RemotableQuickFinder;
27  import org.kuali.rice.core.api.util.RiceKeyConstants;
28  import org.kuali.rice.core.framework.persistence.ojb.conversion.OjbCharBooleanConversion;
29  import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
30  import org.kuali.rice.krad.bo.Attachment;
31  import org.kuali.rice.krad.bo.BusinessObject;
32  import org.kuali.rice.krad.bo.DocumentHeader;
33  import org.kuali.rice.krad.bo.InactivatableFromTo;
34  import org.kuali.rice.krad.bo.PersistableBusinessObject;
35  import org.kuali.rice.krad.dao.DocumentDao;
36  import org.kuali.rice.krad.dao.DocumentHeaderDao;
37  import org.kuali.rice.krad.dao.LookupDao;
38  import org.kuali.rice.krad.dao.MaintenanceDocumentDao;
39  import org.kuali.rice.krad.data.DataObjectService;
40  import org.kuali.rice.krad.data.DataObjectUtils;
41  import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
42  import org.kuali.rice.krad.datadictionary.DataObjectEntry;
43  import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition;
44  import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
45  import org.kuali.rice.krad.datadictionary.SupportAttributeDefinition;
46  import org.kuali.rice.krad.document.Document;
47  import org.kuali.rice.krad.exception.ValidationException;
48  import org.kuali.rice.krad.lookup.LookupUtils;
49  import org.kuali.rice.krad.maintenance.MaintenanceLock;
50  import org.kuali.rice.krad.service.BusinessObjectService;
51  import org.kuali.rice.krad.service.DataDictionaryService;
52  import org.kuali.rice.krad.service.DataObjectMetaDataService;
53  import org.kuali.rice.krad.service.KRADServiceLocator;
54  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
55  import org.kuali.rice.krad.service.KualiModuleService;
56  import org.kuali.rice.krad.service.LegacyDataAdapter;
57  import org.kuali.rice.krad.service.ModuleService;
58  import org.kuali.rice.krad.service.PersistenceService;
59  import org.kuali.rice.krad.service.PersistenceStructureService;
60  import org.kuali.rice.krad.uif.UifPropertyPaths;
61  import org.kuali.rice.krad.uif.service.ViewDictionaryService;
62  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
63  import org.kuali.rice.krad.util.ForeignKeyFieldsPopulationState;
64  import org.kuali.rice.krad.util.GlobalVariables;
65  import org.kuali.rice.krad.util.KRADConstants;
66  import org.kuali.rice.krad.util.KRADPropertyConstants;
67  import org.kuali.rice.krad.util.KRADUtils;
68  import org.kuali.rice.krad.util.LegacyUtils;
69  import org.kuali.rice.krad.util.ObjectUtils;
70  import org.springframework.beans.factory.annotation.Required;
71  
72  import java.lang.reflect.InvocationTargetException;
73  import java.util.ArrayList;
74  import java.util.Collection;
75  import java.util.Collections;
76  import java.util.Date;
77  import java.util.HashMap;
78  import java.util.Iterator;
79  import java.util.List;
80  import java.util.Map;
81  import java.util.TreeMap;
82  import java.util.UUID;
83  
84  /**
85  *
86   */
87  @Deprecated
88  public class KNSLegacyDataAdapterImpl implements LegacyDataAdapter{
89      private BusinessObjectService businessObjectService;
90      private PersistenceService persistenceService;
91      private LookupDao lookupDao;
92      private LookupCriteriaGenerator lookupCriteriaGenerator;
93      private DateTimeService dateTimeService;
94      private DatabasePlatform databasePlatform;
95  
96      private DocumentHeaderDao documentHeaderDaoOjb;
97      private DocumentDao documentDao;
98      private MaintenanceDocumentDao maintenanceDocumentDaoOjb;
99  
100     private PersistenceStructureService persistenceStructureService;
101     private DataObjectMetaDataService dataObjectMetaDataService;
102     private ConfigurationService kualiConfigurationService;
103     private KualiModuleService kualiModuleService;
104     private DataDictionaryService dataDictionaryService;
105     private DataObjectService dataObjectService;
106     private ViewDictionaryService viewDictionaryService;
107 
108     @Override
109     public <T> T save(T dataObject) {
110         if (dataObject instanceof Collection) {
111             Collection<Object> newList = new ArrayList<Object>(((Collection) dataObject).size());
112             for (Object obj : (Collection<?>) dataObject) {
113                 newList.add(save(obj));
114             }
115             return (T) newList;
116         } else {
117            return (T) businessObjectService.save((PersistableBusinessObject) dataObject);
118         }
119     }
120 
121     @Override
122     public <T> T linkAndSave(T dataObject) {
123        return (T) businessObjectService.linkAndSave((PersistableBusinessObject) dataObject);
124     }
125 
126     @Override
127     public <T> T saveDocument(T document) {
128         return (T) documentDao.save((Document) document);
129     }
130 
131     @Override
132     public <T> T findByPrimaryKey(Class<T> clazz, Map<String, ?> primaryKeys) {
133         return (T) businessObjectService.findByPrimaryKey((Class<BusinessObject>) clazz, primaryKeys);
134     }
135 
136     @Override
137     public <T> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey) {
138         return (T) businessObjectService.findBySinglePrimaryKey((Class<BusinessObject>) clazz, primaryKey);
139     }
140 
141     @Override
142     public void delete(Object dataObject) {
143         if (dataObject instanceof Collection) {
144             for (Object dobj : (Collection) dataObject) {
145                 delete(dobj);
146             }
147         } else {
148             businessObjectService.delete((PersistableBusinessObject) dataObject);
149         }
150     }
151 
152     @Override
153     public void deleteMatching(Class<?> type, Map<String, ?> fieldValues) {
154         businessObjectService.deleteMatching(type, fieldValues);
155     }
156 
157     @Override
158     public <T> T retrieve(T dataObject) {
159         return (T) businessObjectService.retrieve((PersistableBusinessObject) dataObject);
160     }
161 
162     @Override
163     public <T> Collection<T> findAll(Class<T> clazz) {
164         // just find all objects of given type without any attribute criteria
165         return findMatching(clazz, Collections.<String, Object>emptyMap());
166     }
167 
168     @Override
169     public <T> Collection<T> findMatching(Class<T> clazz, Map<String, ?> fieldValues) {
170         return (Collection<T>) businessObjectService.findMatching((Class<BusinessObject>) clazz, fieldValues);
171     }
172 
173     @Override
174     public <T> Collection<T> findMatchingOrderBy(Class<T> clazz, Map<String, ?> fieldValues, String sortField,
175             boolean sortAscending) {
176         return (Collection<T>) businessObjectService.findMatchingOrderBy((Class<BusinessObject>) clazz, fieldValues,
177                     sortField, sortAscending);
178     }
179 
180     @Override
181     public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject) {
182         return persistenceService.getPrimaryKeyFieldValues(dataObject);
183     }
184 
185     @Override
186     public void retrieveNonKeyFields(Object persistableObject) {
187         persistenceService.retrieveNonKeyFields(persistableObject);
188     }
189 
190     @Override
191     public void retrieveReferenceObject(Object persistableObject, String referenceObjectName) {
192         persistenceService.retrieveReferenceObject(persistableObject, referenceObjectName);
193     }
194 
195     @Override
196     public void refreshAllNonUpdatingReferences(Object persistableObject) {
197         if (LegacyUtils.useLegacyForObject(persistableObject)) {
198             persistenceService.refreshAllNonUpdatingReferences((PersistableBusinessObject) persistableObject);
199         } else {
200             throw new UnsupportedOperationException("refreshAllNonUpdatingReferences not supported in KRAD");
201         }
202     }
203 
204     @Override
205     public boolean isProxied(Object object) {
206         return persistenceService.isProxied(object);
207     }
208 
209     @Override
210     public Object resolveProxy(Object o) {
211         return persistenceService.resolveProxy(o);
212     }
213 
214     // Lookup methods
215 
216     @Override
217     public <T> Collection<T> findCollectionBySearchHelper(Class<T> dataObjectClass, Map<String, String> formProperties,
218             boolean unbounded, boolean allPrimaryKeyValuesPresentAndNotWildcard, Integer searchResultsLimit) {
219             return lookupDao.findCollectionBySearchHelper(dataObjectClass, formProperties, unbounded,
220                     allPrimaryKeyValuesPresentAndNotWildcard, searchResultsLimit);
221     }
222 
223     /**
224      *
225      * @param dataObjectClass the dataobject class
226      * @param formProperties the incoming lookup form properties
227      * @param unbounded whether the search is unbounded
228      * @param searchResultsLimit the searchResultsLimit; null implies use of default KNS value if set for the class
229      * @param <T> the data object type
230      * @return collection of lookup results
231      */
232     protected <T> Collection<T> performDataObjectServiceLookup(Class<T> dataObjectClass,
233             Map<String, String> formProperties, boolean unbounded, boolean allPrimaryKeyValuesPresentAndNotWildcard,
234             Integer searchResultsLimit) {
235         if (!unbounded && searchResultsLimit == null) {
236             // use KRAD LookupUtils.getSearchResultsLimit instead of KNS version. we have no LookupForm, so pass null, only the class will be used
237             //searchResultsLimit = LookupUtils.getSearchResultsLimit(example, null);
238             searchResultsLimit = org.kuali.rice.kns.lookup.LookupUtils.getSearchResultsLimit(dataObjectClass);
239         }
240         QueryByCriteria.Builder query = lookupCriteriaGenerator.generateCriteria(dataObjectClass, formProperties,
241                 allPrimaryKeyValuesPresentAndNotWildcard);
242         if (!unbounded && searchResultsLimit != null) {
243             query.setMaxResults(searchResultsLimit);
244         }
245 
246         Collection<T> results = dataObjectService.findMatching(dataObjectClass, query.build()).getResults();
247         return filterCurrentDataObjects(dataObjectClass, results, formProperties);
248     }
249 
250     protected <T> Collection<T> filterCurrentDataObjects(Class<T> dataObjectClass, Collection<T> unfiltered,
251             Map<String, String> formProps) {
252         if (InactivatableFromTo.class.isAssignableFrom(dataObjectClass)) {
253             Boolean currentSpecifier = lookupCriteriaCurrentSpecifier(formProps);
254             if (currentSpecifier != null) {
255                 List<InactivatableFromTo> onlyCurrent =
256                         KRADServiceLocator.getInactivateableFromToService().filterOutNonCurrent(new ArrayList(
257                                 unfiltered), new Date(LookupUtils.getActiveDateTimestampForCriteria(formProps)
258                                 .getTime()));
259                 if (currentSpecifier) {
260                     return (Collection<T>) onlyCurrent;
261                 } else {
262                     unfiltered.removeAll(onlyCurrent);
263                     return unfiltered;
264                 }
265             }
266         }
267         return unfiltered;
268     }
269 
270     protected Boolean lookupCriteriaCurrentSpecifier(Map<String, String> formProps) {
271         String value = formProps.get(KRADPropertyConstants.CURRENT);
272         if (StringUtils.isNotBlank(value)) {
273             // FIXME: use something more portable than this direct OJB converter
274             String currentBooleanStr = (String) new OjbCharBooleanConversion().javaToSql(value);
275             if (OjbCharBooleanConversion.DATABASE_BOOLEAN_TRUE_STRING_REPRESENTATION.equals(currentBooleanStr)) {
276                 return Boolean.TRUE;
277             } else if (OjbCharBooleanConversion.DATABASE_BOOLEAN_FALSE_STRING_REPRESENTATION.equals(
278                     currentBooleanStr)) {
279                 return Boolean.FALSE;
280             }
281         }
282         return null;
283     }
284 
285     @Override
286     public <T> T findObjectBySearch(Class<T> type, Map<String, String> formProps) {
287         return lookupDao.findObjectByMap(type, formProps);
288     }
289 
290     /**
291      * Returns whether all primary key values are specified in the lookup  map and do not contain any wildcards
292      *
293      * @param boClass the bo class to lookup
294      * @param formProps the incoming form/lookup properties
295      * @return whether all primary key values are specified in the lookup  map and do not contain any wildcards
296      */
297     @Override
298     public boolean allPrimaryKeyValuesPresentAndNotWildcard(Class<?> boClass, Map<String, String> formProps) {
299         List<String> pkFields = listPrimaryKeyFieldNames(boClass);
300         Iterator<String> pkIter = pkFields.iterator();
301         boolean returnVal = true;
302         while (returnVal && pkIter.hasNext()) {
303             String pkName = pkIter.next();
304             String pkValue = formProps.get(pkName);
305 
306             if (StringUtils.isBlank(pkValue)) {
307                 returnVal = false;
308             } else {
309                 for (SearchOperator op : SearchOperator.QUERY_CHARACTERS) {
310                     if (pkValue.contains(op.op())) {
311                         returnVal = false;
312                         break;
313                     }
314                 }
315             }
316         }
317         return returnVal;
318     }
319 
320     @Override
321     public Attachment getAttachmentByNoteId(Long noteId) {
322         return businessObjectService.findBySinglePrimaryKey(Attachment.class, noteId);
323     }
324 
325     @Override
326     public DocumentHeader getByDocumentHeaderId(String id) {
327         return this.documentHeaderDaoOjb.getByDocumentHeaderId(id);
328     }
329 
330     @Override
331     @Deprecated
332     public Class getDocumentHeaderBaseClass() {
333         return this.documentHeaderDaoOjb.getDocumentHeaderBaseClass();
334     }
335 
336     @Override
337     public void deleteLocks(String documentNumber) {
338         businessObjectService.deleteMatching(MaintenanceLock.class, Collections.singletonMap("documentNumber",
339                     documentNumber));
340     }
341 
342     @Override
343     public String getLockingDocumentNumber(String lockingRepresentation, String documentNumber) {
344             return maintenanceDocumentDaoOjb.getLockingDocumentNumber(lockingRepresentation, documentNumber);
345     }
346 
347     @Override
348     public void storeLocks(List<MaintenanceLock> maintenanceLocks) {
349         if (maintenanceLocks.isEmpty()) {
350             return;
351         }
352         businessObjectService.save(maintenanceLocks);
353     }
354 
355     @Override
356     public List<String> listPrimaryKeyFieldNames(Class<?> type) {
357         List<String> keys = new ArrayList<String>();
358         if (isPersistable(type)) {
359             keys = persistenceStructureService.listPrimaryKeyFieldNames(type);
360         } else {
361             ModuleService responsibleModuleService = kualiModuleService.getResponsibleModuleService(type);
362             if (responsibleModuleService != null && responsibleModuleService.isExternalizable(type)) {
363                 keys = responsibleModuleService.listPrimaryKeyFieldNames(type);
364             } else {
365                 // check the Data Dictionary for PK's of non PBO/EBO
366                 List<String> pks = dataDictionaryService.getDataDictionary().getDataObjectEntry(type.getName())
367                         .getPrimaryKeys();
368                 if (pks != null && !pks.isEmpty()) {
369                     keys = pks;
370                 }
371             }
372         }
373         return keys;
374     }
375 
376     /**
377      * LookupServiceImpl calls BusinessObjectMetaDataService to listPrimaryKeyFieldNames.
378      * The BusinessObjectMetaDataService goes beyond the PersistenceStructureService to consult
379      * the associated ModuleService in determining the primary key field names.
380      * TODO: Do we need both listPrimaryKeyFieldNames/persistenceStructureService and
381      * listPrimaryKeyFieldNamesConsultingAllServices/businesObjectMetaDataService or
382      * can the latter superset be used for the former?
383      *
384      * @param type the data object class
385      * @return list of primary key field names, consulting persistence structure service, module service and
386      *         datadictionary
387      */
388     protected List<String> listPrimaryKeyFieldNamesConsultingAllServices(Class<?> type) {
389         return dataObjectMetaDataService.listPrimaryKeyFieldNames(type);
390     }
391 
392     @Override
393     public Class<?> determineCollectionObjectType(Class<?> containingType, String collectionPropertyName) {
394         final Class<?> collectionObjectType;
395         if (isPersistable(containingType)) {
396             Map<String, Class> collectionClasses = new HashMap<String, Class>();
397             collectionClasses = persistenceStructureService.listCollectionObjectTypes(containingType);
398             collectionObjectType = collectionClasses.get(collectionPropertyName);
399         } else {
400             throw new RuntimeException(
401                     "Can't determine the Class of Collection elements because persistenceStructureService.isPersistable("
402                             + containingType.getName()
403                             + ") returns false.");
404         }
405         return collectionObjectType;
406 
407     }
408 
409     @Override
410     public Map<String, ?> getPrimaryKeyFieldValuesDOMDS(Object dataObject) {
411         return dataObjectMetaDataService.getPrimaryKeyFieldValues(dataObject);
412     }
413 
414     @Override
415     public boolean equalsByPrimaryKeys(Object do1, Object do2) {
416         return dataObjectMetaDataService.equalsByPrimaryKeys(do1, do2);
417     }
418 
419     @Override
420     public PersistableBusinessObject toPersistableBusinessObject(Object object) {
421         if (object instanceof PersistableBusinessObject && isPersistable(object.getClass())) {
422             return (PersistableBusinessObject) object;
423         }
424         throw new IllegalArgumentException("Given object was not a PersistableBusinessObject");
425     }
426 
427     @Override
428     public void materializeAllSubObjects(Object object) {
429         ObjectUtils.materializeAllSubObjects((PersistableBusinessObject) object);
430     }
431 
432     @Override
433     public Class<?> getPropertyType(Object object, String propertyName) {
434         return ObjectUtils.getPropertyType(object, propertyName,
435                     KRADServiceLocator.getPersistenceStructureService());
436     }
437 
438     @Override
439     public boolean isLockable(Object object) {
440         return isPersistable(object.getClass());
441     }
442 
443     @Override
444     public void verifyVersionNumber(Object dataObject) {
445         if (isPersistable(dataObject.getClass())) {
446             PersistableBusinessObject pbObject = businessObjectService.retrieve((PersistableBusinessObject) dataObject);
447             Long pbObjectVerNbr = KRADUtils.isNull(pbObject) ? null : pbObject.getVersionNumber();
448             Long newObjectVerNbr = ((PersistableBusinessObject) dataObject).getVersionNumber();
449             if (pbObjectVerNbr != null && !(pbObjectVerNbr.equals(newObjectVerNbr))) {
450                 GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS,
451                         RiceKeyConstants.ERROR_VERSION_MISMATCH);
452                 throw new ValidationException(
453                         "Version mismatch between the local business object and the database business object");
454             }
455         }
456     }
457 
458     @Override
459     public RemotableQuickFinder.Builder createQuickFinder(Class<?> containingClass, String attributeName) {
460         return createQuickFinderLegacy(containingClass, attributeName);
461     }
462 
463     /**
464      * Legacy implementation of createQuickFinder. Uses the legacy DataObjectMetadataService.
465      */
466     protected RemotableQuickFinder.Builder createQuickFinderLegacy(Class<?> containingClass, String attributeName) {
467         Object sampleComponent;
468         try {
469             sampleComponent = containingClass.newInstance();
470         } catch (InstantiationException e) {
471             throw new RiceRuntimeException(e);
472         } catch (IllegalAccessException e) {
473             throw new RiceRuntimeException(e);
474         }
475 
476         String lookupClassName = null;
477         Map<String, String> fieldConversions = new HashMap<String, String>();
478         Map<String, String> lookupParameters = new HashMap<String, String>();
479 
480         org.kuali.rice.krad.bo.DataObjectRelationship relationship =
481                 getDataObjectRelationship(sampleComponent, containingClass, attributeName, "",
482                         true, true, false);
483         if (relationship != null) {
484             lookupClassName = relationship.getRelatedClass().getName();
485 
486             for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
487                 String fromField = entry.getValue();
488                 String toField = entry.getKey();
489                 fieldConversions.put(fromField, toField);
490             }
491 
492             for (Map.Entry<String, String> entry : relationship.getParentToChildReferences().entrySet()) {
493                 String fromField = entry.getKey();
494                 String toField = entry.getValue();
495 
496                 if (relationship.getUserVisibleIdentifierKey() == null || relationship.getUserVisibleIdentifierKey()
497                         .equals(fromField)) {
498                     lookupParameters.put(fromField, toField);
499                 }
500             }
501         } else {
502             // check for title attribute and if match build lookup to component class using pk fields
503             String titleAttribute = dataObjectMetaDataService.getTitleAttribute(containingClass);
504             if (StringUtils.equals(titleAttribute, attributeName)) {
505                 lookupClassName = containingClass.getName();
506 
507                 List<String> pkAttributes = dataObjectMetaDataService.listPrimaryKeyFieldNames(containingClass);
508                 for (String pkAttribute : pkAttributes) {
509                     fieldConversions.put(pkAttribute, pkAttribute);
510                     if (!StringUtils.equals(pkAttribute, attributeName)) {
511                         lookupParameters.put(pkAttribute, pkAttribute);
512                     }
513                 }
514             }
515         }
516 
517         if (StringUtils.isNotBlank(lookupClassName)) {
518             String baseUrl = kualiConfigurationService.getPropertyValueAsString(KRADConstants.KRAD_LOOKUP_URL_KEY);
519             RemotableQuickFinder.Builder builder = RemotableQuickFinder.Builder.create(baseUrl, lookupClassName);
520             builder.setLookupParameters(lookupParameters);
521             builder.setFieldConversions(fieldConversions);
522 
523             return builder;
524         }
525 
526         return null;
527     }
528 
529 
530     @Override
531     public boolean isReferenceUpdatable(Class<?> type, String referenceName) {
532         return persistenceStructureService.isReferenceUpdatable(type, referenceName);
533     }
534 
535     @SuppressWarnings("rawtypes")
536     @Override
537     public Map<String, Class> listReferenceObjectFields(Class<?> type) {
538         return persistenceStructureService.listReferenceObjectFields(type);
539     }
540 
541     @Override
542     public boolean isCollectionUpdatable(Class<?> type, String collectionName) {
543         return persistenceStructureService.isCollectionUpdatable(type, collectionName);
544     }
545 
546     @Override
547     public Map<String, Class> listCollectionObjectTypes(Class<?> type) {
548         return persistenceStructureService.listCollectionObjectTypes(type);
549     }
550 
551     @Override
552     public BusinessObject getReferenceIfExists(BusinessObject bo, String referenceName) {
553         return businessObjectService.getReferenceIfExists(bo, referenceName);
554     }
555 
556     @Override
557     public boolean allForeignKeyValuesPopulatedForReference(PersistableBusinessObject bo, String referenceName) {
558         return persistenceService.allForeignKeyValuesPopulatedForReference(bo, referenceName);
559     }
560 
561     /**
562      * gets the relationship that the attribute represents on the class
563      *
564      * @param c - the class to which the attribute belongs
565      * @param attributeName - property name for the attribute
566      * @return a relationship definition for the attribute
567      */
568     @Override
569     public RelationshipDefinition getDictionaryRelationship(Class<?> c, String attributeName) {
570         DataDictionaryEntry entryBase =
571                 KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(
572                         c.getName());
573         if (entryBase == null) {
574             return null;
575         }
576 
577         RelationshipDefinition relationship = null;
578 
579         List<RelationshipDefinition> ddRelationships = entryBase.getRelationships();
580 
581         int minKeys = Integer.MAX_VALUE;
582         for (RelationshipDefinition def : ddRelationships) {
583             // favor key sizes of 1 first
584             if (def.getPrimitiveAttributes().size() == 1) {
585                 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
586                     if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
587                             attributeName)) {
588                         relationship = def;
589                         minKeys = 1;
590                         break;
591                     }
592                 }
593             } else if (def.getPrimitiveAttributes().size() < minKeys) {
594                 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
595                     if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
596                             attributeName)) {
597                         relationship = def;
598                         minKeys = def.getPrimitiveAttributes().size();
599                         break;
600                     }
601                 }
602             }
603         }
604 
605         // check the support attributes
606         if (relationship == null) {
607             for (RelationshipDefinition def : ddRelationships) {
608                 if (def.hasIdentifier()) {
609                     if (def.getIdentifier().getSourceName().equals(attributeName)) {
610                         relationship = def;
611                     }
612                 }
613             }
614         }
615 
616         return relationship;
617     }
618 
619     /**
620      * @see org.kuali.rice.krad.service.LegacyDataAdapter
621      */
622     @Override
623     public String getTitleAttribute(Class<?> dataObjectClass) {
624         String titleAttribute = null;
625         DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
626         if (entry != null) {
627             titleAttribute = entry.getTitleAttribute();
628         }
629         return titleAttribute;
630     }
631 
632     /**
633      * @param dataObjectClass
634      * @return DataObjectEntry for the given dataObjectClass, or null if
635      *         there is none
636      * @throws IllegalArgumentException if the given Class is null
637      */
638     protected DataObjectEntry getDataObjectEntry(Class<?> dataObjectClass) {
639         if (dataObjectClass == null) {
640             throw new IllegalArgumentException("invalid (null) dataObjectClass");
641         }
642 
643         DataObjectEntry entry = dataDictionaryService.getDataDictionary().getDataObjectEntry(dataObjectClass.getName());
644 
645         return entry;
646     }
647 
648     /**
649      * @see org.kuali.rice.krad.service.LegacyDataAdapter#areNotesSupported(Class)
650      */
651     @Override
652     public boolean areNotesSupported(Class<?> dataObjectClass) {
653         boolean hasNotesSupport = false;
654 
655         DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
656         if (entry != null) {
657             hasNotesSupport = entry.isBoNotesEnabled();
658         }
659 
660         return hasNotesSupport;
661     }
662 
663     /**
664      * Grabs primary key fields and sorts them if sort field names is true
665      *
666      * @param dataObject
667      * @param sortFieldNames
668      * @return Map of sorted primary key field values
669      */
670     public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject, boolean sortFieldNames) {
671         Map<String, Object> keyFieldValues = (Map<String, Object>) getPrimaryKeyFieldValues(dataObject);
672         if (sortFieldNames) {
673             Map<String, Object> sortedKeyFieldValues = new TreeMap<String, Object>();
674             sortedKeyFieldValues.putAll(keyFieldValues);
675             return sortedKeyFieldValues;
676         }
677         return keyFieldValues;
678     }
679 
680     /**
681      * @see org.kuali.rice.krad.service.DataObjectMetaDataService#getDataObjectIdentifierString
682      */
683     @Override
684     public String getDataObjectIdentifierString(Object dataObject) {
685         String identifierString = "";
686 
687         if (dataObject == null) {
688             identifierString = "Null";
689             return identifierString;
690         }
691 
692         Class<?> dataObjectClass = dataObject.getClass();
693         // if Legacy and a PersistableBusinessObject or if not Legacy and implement GlobalLyUnique use the object id field
694         if ((PersistableBusinessObject.class.isAssignableFrom(
695                 dataObjectClass)) || (!LegacyUtils.useLegacyForObject(dataObject) && GloballyUnique.class
696                 .isAssignableFrom(dataObjectClass))) {
697             String objectId = ObjectPropertyUtils.getPropertyValue(dataObject, UifPropertyPaths.OBJECT_ID);
698             if (StringUtils.isBlank(objectId)) {
699                 objectId = UUID.randomUUID().toString();
700                 ObjectPropertyUtils.setPropertyValue(dataObject, UifPropertyPaths.OBJECT_ID, objectId);
701             }
702         }
703         return identifierString;
704     }
705 
706     @Override
707     public Class<?> getInquiryObjectClassIfNotTitle(Object dataObject, String propertyName) {
708         Class<?> objectClass = ObjectUtils.materializeClassForProxiedObject(dataObject);
709         org.kuali.rice.krad.bo.DataObjectRelationship relationship =
710                 dataObjectMetaDataService.getDataObjectRelationship(dataObject, objectClass, propertyName, "", true,
711                         false, true);
712         if (relationship != null) {
713             return relationship.getRelatedClass();
714         }
715         return null;
716     }
717 
718     @Override
719     public Map<String, String> getInquiryParameters(Object dataObject, List<String> keys, String propertyName) {
720         Map<String, String> inquiryParameters = new HashMap<String, String>();
721         Class<?> objectClass = ObjectUtils.materializeClassForProxiedObject(dataObject);
722         org.kuali.rice.krad.bo.DataObjectRelationship relationship =
723                 dataObjectMetaDataService.getDataObjectRelationship(dataObject, objectClass, propertyName, "", true,
724                         false, true);
725         for (String keyName : keys) {
726             String keyConversion = keyName;
727             if (relationship != null) {
728                 keyConversion = relationship.getParentAttributeForChildAttribute(keyName);
729             } else if (DataObjectUtils.isNestedAttribute(propertyName)) {
730                 String nestedAttributePrefix = DataObjectUtils.getNestedAttributePrefix(propertyName);
731                 keyConversion = nestedAttributePrefix + "." + keyName;
732             }
733             inquiryParameters.put(keyConversion, keyName);
734         }
735         return inquiryParameters;
736     }
737 
738     @Override
739     public boolean hasLocalLookup(Class<?> dataObjectClass) {
740         return dataObjectMetaDataService.hasLocalLookup(dataObjectClass);
741     }
742 
743     @Override
744     public boolean hasLocalInquiry(Class<?> dataObjectClass) {
745         return dataObjectMetaDataService.hasLocalInquiry(dataObjectClass);
746     }
747 
748     @Override
749     public org.kuali.rice.krad.bo.DataObjectRelationship getDataObjectRelationship(Object dataObject,
750             Class<?> dataObjectClass, String attributeName, String attributePrefix, boolean keysOnly,
751             boolean supportsLookup, boolean supportsInquiry) {
752         RelationshipDefinition ddReference = getDictionaryRelationship(dataObjectClass, attributeName);
753         return dataObjectMetaDataService.getDataObjectRelationship(dataObject, dataObjectClass, attributeName,
754                     attributePrefix, keysOnly, supportsLookup, supportsInquiry);
755 
756     }
757 
758 
759 
760     protected org.kuali.rice.krad.bo.DataObjectRelationship populateRelationshipFromDictionaryReference(Class<?> dataObjectClass,
761             RelationshipDefinition ddReference, String attributePrefix, boolean keysOnly) {
762         org.kuali.rice.krad.bo.DataObjectRelationship relationship = new org.kuali.rice.krad.bo.DataObjectRelationship(dataObjectClass,
763                 ddReference.getObjectAttributeName(), ddReference.getTargetClass());
764 
765         for (PrimitiveAttributeDefinition def : ddReference.getPrimitiveAttributes()) {
766             if (StringUtils.isNotBlank(attributePrefix)) {
767                 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
768                         def.getTargetName());
769             } else {
770                 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
771             }
772         }
773 
774         if (!keysOnly) {
775             for (SupportAttributeDefinition def : ddReference.getSupportAttributes()) {
776                 if (StringUtils.isNotBlank(attributePrefix)) {
777                     relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
778                             def.getTargetName());
779                     if (def.isIdentifier()) {
780                         relationship.setUserVisibleIdentifierKey(attributePrefix + "." + def.getSourceName());
781                     }
782                 } else {
783                     relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
784                     if (def.isIdentifier()) {
785                         relationship.setUserVisibleIdentifierKey(def.getSourceName());
786                     }
787                 }
788             }
789         }
790 
791         return relationship;
792     }
793 
794     public boolean isPersistable(Class<?> dataObjectClass) {
795         return persistenceStructureService.isPersistable(dataObjectClass);
796     }
797 
798     @Override
799     public void setObjectPropertyDeep(Object bo, String propertyName, Class type,
800             Object propertyValue) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
801         ObjectUtils.setObjectPropertyDeep(bo,propertyName,type,propertyValue);
802     }
803 
804     protected org.kuali.rice.krad.bo.DataObjectRelationship getRelationshipMetadata(Class<?> dataObjectClass,
805             String attributeName, String attributePrefix) {
806 
807         RelationshipDefinition relationshipDefinition = getDictionaryRelationship(dataObjectClass, attributeName);
808         if (relationshipDefinition == null) {
809             return null;
810         }
811 
812         org.kuali.rice.krad.bo.DataObjectRelationship dataObjectRelationship =
813                 new org.kuali.rice.krad.bo.DataObjectRelationship(relationshipDefinition.getSourceClass(),
814                         relationshipDefinition.getObjectAttributeName(), relationshipDefinition.getTargetClass());
815 
816         if (!StringUtils.isEmpty(attributePrefix)) {
817             attributePrefix += ".";
818         }
819 
820         List<PrimitiveAttributeDefinition> primitives = relationshipDefinition.getPrimitiveAttributes();
821         for (PrimitiveAttributeDefinition primitiveAttributeDefinition : primitives) {
822             dataObjectRelationship.getParentToChildReferences().put(
823                     attributePrefix + primitiveAttributeDefinition.getSourceName(),
824                     primitiveAttributeDefinition.getTargetName());
825         }
826 
827         return dataObjectRelationship;
828     }
829 
830     protected boolean classHasSupportedFeatures(Class relationshipClass, boolean supportsLookup,
831             boolean supportsInquiry) {
832         boolean hasSupportedFeatures = true;
833         if (supportsLookup && !getViewDictionaryService().isLookupable(relationshipClass)) {
834             hasSupportedFeatures = false;
835         }
836         if (supportsInquiry && !getViewDictionaryService().isInquirable(relationshipClass)) {
837             hasSupportedFeatures = false;
838         }
839 
840         return hasSupportedFeatures;
841     }
842 
843     @Override
844     public boolean isNull(Object object){
845          return ObjectUtils.isNull(object);
846     }
847 
848     @Override
849     public void setObjectProperty(Object bo, String propertyName, Class propertyType,
850             Object propertyValue) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
851         ObjectUtils.setObjectProperty(bo,propertyName,propertyType,propertyValue);
852     }
853 
854     public Class materializeClassForProxiedObject(Object object){
855         return ObjectUtils.materializeClassForProxiedObject(object);
856     }
857 
858     public Object getNestedValue(Object bo, String fieldName){
859         return ObjectUtils.getNestedValue(bo,fieldName);
860     }
861 
862     public Object createNewObjectFromClass(Class clazz){
863         return ObjectUtils.createNewObjectFromClass(clazz);
864     }
865 
866     @Override
867     public ForeignKeyFieldsPopulationState getForeignKeyFieldsPopulationState(Object dataObject, String referenceName) {
868         return persistenceStructureService.getForeignKeyFieldsPopulationState(
869                     (PersistableBusinessObject) dataObject, referenceName);
870     }
871 
872     @Override
873     public Map<String, String> getForeignKeysForReference(Class<?> clazz, String attributeName) {
874         return persistenceStructureService.getForeignKeysForReference(clazz, attributeName);
875     }
876 
877     @Override
878     public boolean hasPrimaryKeyFieldValues(Object dataObject) {
879         return persistenceStructureService.hasPrimaryKeyFieldValues(dataObject);
880     }
881 
882     @Required
883     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
884         this.businessObjectService = businessObjectService;
885     }
886 
887     @Required
888     public void setPersistenceService(PersistenceService persistenceService) {
889         this.persistenceService = persistenceService;
890     }
891 
892     @Required
893     public void setLookupDao(LookupDao lookupDao) {
894         this.lookupDao = lookupDao;
895     }
896 
897     @Required
898     public void setLookupCriteriaGenerator(LookupCriteriaGenerator lookupCriteriaGenerator) {
899         this.lookupCriteriaGenerator = lookupCriteriaGenerator;
900     }
901 
902     @Required
903     public void setDateTimeService(DateTimeService dts) {
904         this.dateTimeService = dts;
905     }
906 
907     @Required
908     public void setDatabasePlatform(DatabasePlatform databasePlatform) {
909         this.databasePlatform = databasePlatform;
910     }
911 
912     @Required
913     public void setDocumentHeaderDaoOjb(DocumentHeaderDao documentHeaderDaoOjb) {
914         this.documentHeaderDaoOjb = documentHeaderDaoOjb;
915     }
916 
917     @Required
918     public void setMaintenanceDocumentDaoOjb(MaintenanceDocumentDao maintenanceDocumentDaoOjb) {
919         this.maintenanceDocumentDaoOjb = maintenanceDocumentDaoOjb;
920     }
921 
922     //@Required
923     //public void setNoteDaoOjb(NoteDao noteDaoOjb) {
924     //    this.noteDaoOjb = noteDaoOjb;
925     //}
926 
927     @Required
928     public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
929         this.persistenceStructureService = persistenceStructureService;
930     }
931 
932     @Required
933     public void setDataObjectMetaDataService(DataObjectMetaDataService dataObjectMetaDataService) {
934         this.dataObjectMetaDataService = dataObjectMetaDataService;
935     }
936 
937     @Required
938     public void setKualiConfigurationService(ConfigurationService kualiConfigurationService) {
939         this.kualiConfigurationService = kualiConfigurationService;
940     }
941 
942     @Required
943     public void setKualiModuleService(KualiModuleService kualiModuleService) {
944         this.kualiModuleService = kualiModuleService;
945     }
946 
947     @Required
948     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
949         this.dataDictionaryService = dataDictionaryService;
950     }
951 
952     @Required
953     public void setDocumentDao(DocumentDao documentDao) {
954         this.documentDao = documentDao;
955     }
956 
957     public DataObjectService getDataObjectService() {
958         return dataObjectService;
959     }
960 
961     public void setDataObjectService(DataObjectService dataObjectService) {
962         this.dataObjectService = dataObjectService;
963     }
964 
965     public ViewDictionaryService getViewDictionaryService() {
966         return viewDictionaryService;
967     }
968 
969     public void setViewDictionaryService(ViewDictionaryService viewDictionaryService) {
970         this.viewDictionaryService = viewDictionaryService;
971     }
972 
973 }