1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.service.impl;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.TreeMap;
24 import java.util.UUID;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.kuali.rice.krad.bo.BusinessObject;
28 import org.kuali.rice.krad.bo.DataObjectRelationship;
29 import org.kuali.rice.krad.bo.PersistableBusinessObject;
30 import org.kuali.rice.krad.datadictionary.BusinessObjectEntry;
31 import org.kuali.rice.krad.datadictionary.DataDictionaryEntry;
32 import org.kuali.rice.krad.datadictionary.DataObjectEntry;
33 import org.kuali.rice.krad.datadictionary.PrimitiveAttributeDefinition;
34 import org.kuali.rice.krad.datadictionary.RelationshipDefinition;
35 import org.kuali.rice.krad.datadictionary.SupportAttributeDefinition;
36 import org.kuali.rice.krad.service.DataDictionaryService;
37 import org.kuali.rice.krad.service.DataObjectMetaDataService;
38 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
39 import org.kuali.rice.krad.service.KualiModuleService;
40 import org.kuali.rice.krad.service.ModuleService;
41 import org.kuali.rice.krad.service.PersistenceStructureService;
42 import org.kuali.rice.krad.uif.UifPropertyPaths;
43 import org.kuali.rice.krad.uif.service.ViewDictionaryService;
44 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
45 import org.kuali.rice.krad.util.ObjectUtils;
46 import org.springframework.beans.BeanWrapper;
47
48
49
50
51 public class DataObjectMetaDataServiceImpl implements DataObjectMetaDataService {
52
53 private DataDictionaryService dataDictionaryService;
54 private KualiModuleService kualiModuleService;
55 private PersistenceStructureService persistenceStructureService;
56 private ViewDictionaryService viewDictionaryService;
57
58
59
60
61 @Override
62 public List<String> listPrimaryKeyFieldNames(Class<?> clazz) {
63 if (persistenceStructureService.isPersistable(clazz)) {
64 return persistenceStructureService.listPrimaryKeyFieldNames(clazz);
65 }
66
67 ModuleService responsibleModuleService = getKualiModuleService().getResponsibleModuleService(clazz);
68 if (responsibleModuleService != null && responsibleModuleService.isExternalizable(clazz)) {
69 return responsibleModuleService.listPrimaryKeyFieldNames(clazz);
70 }
71
72
73 List<String> pks = dataDictionaryService.getDataDictionary().getDataObjectEntry(clazz.getName())
74 .getPrimaryKeys();
75 if (pks != null && !pks.isEmpty()) {
76 return pks;
77 }
78
79 return new ArrayList<String>();
80 }
81
82
83
84
85 @Override
86 public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject) {
87 return getPrimaryKeyFieldValues(dataObject, false);
88 }
89
90
91
92
93
94 @Override
95 public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject, boolean sortFieldNames) {
96 Map<String, Object> keyValueMap;
97
98 if (sortFieldNames) {
99 keyValueMap = new TreeMap<String, Object>();
100 } else {
101 keyValueMap = new HashMap<String, Object>();
102 }
103
104 BeanWrapper wrapper = ObjectPropertyUtils.wrapObject(dataObject);
105
106 List<String> fields = listPrimaryKeyFieldNames(dataObject.getClass());
107 for (String fieldName : fields) {
108 keyValueMap.put(fieldName, wrapper.getPropertyValue(fieldName));
109 }
110
111 return keyValueMap;
112 }
113
114
115
116
117
118 @Override
119 public boolean equalsByPrimaryKeys(Object do1, Object do2) {
120 boolean equal = true;
121
122 if (do1 == null && do2 == null) {
123 equal = true;
124 } else if (do1 == null || do2 == null) {
125 equal = false;
126 } else if (!do1.getClass().getName().equals(do2.getClass().getName())) {
127 equal = false;
128 } else {
129 Map<String, ?> do1Keys = getPrimaryKeyFieldValues(do1);
130 Map<String, ?> do2Keys = getPrimaryKeyFieldValues(do2);
131 for (Iterator<String> iter = do1Keys.keySet().iterator(); iter.hasNext(); ) {
132 String keyName = iter.next();
133 if (do1Keys.get(keyName) != null && do2Keys.get(keyName) != null) {
134 if (!do1Keys.get(keyName).toString().equals(do2Keys.get(keyName).toString())) {
135 equal = false;
136 }
137 } else {
138 equal = false;
139 }
140 }
141 }
142
143 return equal;
144 }
145
146
147
148
149
150
151 public DataObjectRelationship getDataObjectRelationship(Object dataObject, Class<?> dataObjectClass,
152 String attributeName, String attributePrefix, boolean keysOnly, boolean supportsLookup,
153 boolean supportsInquiry) {
154 RelationshipDefinition ddReference = getDictionaryRelationship(dataObjectClass, attributeName);
155
156 return getDataObjectRelationship(ddReference, dataObject, dataObjectClass, attributeName, attributePrefix,
157 keysOnly, supportsLookup, supportsInquiry);
158 }
159
160 protected DataObjectRelationship getDataObjectRelationship(RelationshipDefinition ddReference, Object dataObject,
161 Class<?> dataObjectClass, String attributeName, String attributePrefix, boolean keysOnly,
162 boolean supportsLookup, boolean supportsInquiry) {
163 DataObjectRelationship relationship = null;
164
165
166
167 if (ObjectUtils.isNestedAttribute(attributeName)) {
168 if (ddReference != null) {
169 if (classHasSupportedFeatures(ddReference.getTargetClass(), supportsLookup, supportsInquiry)) {
170 relationship = populateRelationshipFromDictionaryReference(dataObjectClass, ddReference,
171 attributePrefix, keysOnly);
172
173 return relationship;
174 }
175 }
176
177
178 String localPrefix = StringUtils.substringBefore(attributeName, ".");
179 String localAttributeName = StringUtils.substringAfter(attributeName, ".");
180 if (dataObject == null) {
181 dataObject = ObjectUtils.createNewObjectFromClass(dataObjectClass);
182 }
183
184 Object nestedObject = ObjectPropertyUtils.getPropertyValue(dataObject, localPrefix);
185 Class<?> nestedClass = null;
186 if (nestedObject == null) {
187 nestedClass = ObjectPropertyUtils.getPropertyType(dataObject, localPrefix);
188 } else {
189 nestedClass = nestedObject.getClass();
190 }
191
192 String fullPrefix = localPrefix;
193 if (StringUtils.isNotBlank(attributePrefix)) {
194 fullPrefix = attributePrefix + "." + localPrefix;
195 }
196
197 relationship = getDataObjectRelationship(nestedObject, nestedClass, localAttributeName, fullPrefix,
198 keysOnly, supportsLookup, supportsInquiry);
199
200 return relationship;
201 }
202
203
204 int maxSize = Integer.MAX_VALUE;
205
206
207 if (getPersistenceStructureService().isPersistable(dataObjectClass)) {
208 Map<String, DataObjectRelationship> rels = getPersistenceStructureService().getRelationshipMetadata(
209 dataObjectClass, attributeName, attributePrefix);
210 if (rels.size() > 0) {
211 for (DataObjectRelationship rel : rels.values()) {
212 if (rel.getParentToChildReferences().size() < maxSize) {
213 if (classHasSupportedFeatures(rel.getRelatedClass(), supportsLookup, supportsInquiry)) {
214 maxSize = rel.getParentToChildReferences().size();
215 relationship = rel;
216 }
217 }
218 }
219 }
220 } else {
221 ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(dataObjectClass);
222 if (moduleService != null && moduleService.isExternalizable(dataObjectClass)) {
223 relationship = getRelationshipMetadata(dataObjectClass, attributeName, attributePrefix);
224 if ((relationship != null) && classHasSupportedFeatures(relationship.getRelatedClass(), supportsLookup,
225 supportsInquiry)) {
226 return relationship;
227 } else {
228 return null;
229 }
230 }
231 }
232
233 if (ddReference != null && ddReference.getPrimitiveAttributes().size() < maxSize) {
234 if (classHasSupportedFeatures(ddReference.getTargetClass(), supportsLookup, supportsInquiry)) {
235 relationship = populateRelationshipFromDictionaryReference(dataObjectClass, ddReference, null,
236 keysOnly);
237 }
238 }
239
240 return relationship;
241 }
242
243 protected boolean classHasSupportedFeatures(Class relationshipClass, boolean supportsLookup,
244 boolean supportsInquiry) {
245 boolean hasSupportedFeatures = true;
246 if (supportsLookup && !getViewDictionaryService().isLookupable(relationshipClass)) {
247 hasSupportedFeatures = false;
248 }
249 if (supportsInquiry && !getViewDictionaryService().isInquirable(relationshipClass)) {
250 hasSupportedFeatures = false;
251 }
252
253 return hasSupportedFeatures;
254 }
255
256 public RelationshipDefinition getDictionaryRelationship(Class<?> c, String attributeName) {
257 DataDictionaryEntry entryBase = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(
258 c.getName());
259 if (entryBase == null) {
260 return null;
261 }
262
263 RelationshipDefinition relationship = null;
264
265 List<RelationshipDefinition> ddRelationships = entryBase.getRelationships();
266
267 int minKeys = Integer.MAX_VALUE;
268 for (RelationshipDefinition def : ddRelationships) {
269
270 if (def.getPrimitiveAttributes().size() == 1) {
271 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
272 if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
273 attributeName)) {
274 relationship = def;
275 minKeys = 1;
276 break;
277 }
278 }
279 } else if (def.getPrimitiveAttributes().size() < minKeys) {
280 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
281 if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
282 attributeName)) {
283 relationship = def;
284 minKeys = def.getPrimitiveAttributes().size();
285 break;
286 }
287 }
288 }
289 }
290
291
292 if (relationship == null) {
293 for (RelationshipDefinition def : ddRelationships) {
294 if (def.hasIdentifier()) {
295 if (def.getIdentifier().getSourceName().equals(attributeName)) {
296 relationship = def;
297 }
298 }
299 }
300 }
301
302 return relationship;
303 }
304
305 protected DataObjectRelationship populateRelationshipFromDictionaryReference(Class<?> dataObjectClass,
306 RelationshipDefinition ddReference, String attributePrefix, boolean keysOnly) {
307 DataObjectRelationship relationship = new DataObjectRelationship(dataObjectClass,
308 ddReference.getObjectAttributeName(), ddReference.getTargetClass());
309
310 for (PrimitiveAttributeDefinition def : ddReference.getPrimitiveAttributes()) {
311 if (StringUtils.isNotBlank(attributePrefix)) {
312 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
313 def.getTargetName());
314 } else {
315 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
316 }
317 }
318
319 if (!keysOnly) {
320 for (SupportAttributeDefinition def : ddReference.getSupportAttributes()) {
321 if (StringUtils.isNotBlank(attributePrefix)) {
322 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
323 def.getTargetName());
324 if (def.isIdentifier()) {
325 relationship.setUserVisibleIdentifierKey(attributePrefix + "." + def.getSourceName());
326 }
327 } else {
328 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
329 if (def.isIdentifier()) {
330 relationship.setUserVisibleIdentifierKey(def.getSourceName());
331 }
332 }
333 }
334 }
335
336 return relationship;
337 }
338
339 protected DataObjectRelationship getRelationshipMetadata(Class<?> dataObjectClass, String attributeName,
340 String attributePrefix) {
341
342 RelationshipDefinition relationshipDefinition = getDictionaryRelationship(dataObjectClass, attributeName);
343 if (relationshipDefinition == null) {
344 return null;
345 }
346
347 DataObjectRelationship dataObjectRelationship = new DataObjectRelationship(
348 relationshipDefinition.getSourceClass(), relationshipDefinition.getObjectAttributeName(),
349 relationshipDefinition.getTargetClass());
350
351 if (!StringUtils.isEmpty(attributePrefix)) {
352 attributePrefix += ".";
353 }
354
355 List<PrimitiveAttributeDefinition> primitives = relationshipDefinition.getPrimitiveAttributes();
356 for (PrimitiveAttributeDefinition primitiveAttributeDefinition : primitives) {
357 dataObjectRelationship.getParentToChildReferences().put(
358 attributePrefix + primitiveAttributeDefinition.getSourceName(),
359 primitiveAttributeDefinition.getTargetName());
360 }
361
362 return dataObjectRelationship;
363 }
364
365
366
367
368 public String getTitleAttribute(Class<?> dataObjectClass) {
369 String titleAttribute = null;
370
371 DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
372 if (entry != null) {
373 titleAttribute = entry.getTitleAttribute();
374 }
375
376 return titleAttribute;
377 }
378
379
380
381
382 @Override
383 public boolean areNotesSupported(Class<?> dataObjectClass) {
384 boolean hasNotesSupport = false;
385
386 DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
387 if (entry != null) {
388 hasNotesSupport = entry.isBoNotesEnabled();
389 }
390
391 return hasNotesSupport;
392 }
393
394
395
396
397 public String getDataObjectIdentifierString(Object dataObject) {
398 String identifierString = "";
399
400 if (dataObject == null) {
401 identifierString = "Null";
402 return identifierString;
403 }
404
405 Class<?> dataObjectClass = dataObject.getClass();
406
407
408 if (PersistableBusinessObject.class.isAssignableFrom(dataObjectClass)) {
409 String objectId = ObjectPropertyUtils.getPropertyValue(dataObject, UifPropertyPaths.OBJECT_ID);
410 if (StringUtils.isBlank(objectId)) {
411 objectId = UUID.randomUUID().toString();
412 ObjectPropertyUtils.setPropertyValue(dataObject, UifPropertyPaths.OBJECT_ID, objectId);
413 }
414
415 identifierString = objectId;
416 } else {
417
418 Map<String, ?> primaryKeyFieldValues = getPrimaryKeyFieldValues(dataObject, true);
419 for (Map.Entry<String, ?> primaryKeyValue : primaryKeyFieldValues.entrySet()) {
420 if (primaryKeyValue.getValue() == null) {
421 identifierString += "Null";
422 } else {
423 identifierString += primaryKeyValue.getValue();
424 }
425 identifierString += ":";
426 }
427 identifierString = StringUtils.removeEnd(identifierString, ":");
428 }
429
430 return identifierString;
431 }
432
433
434
435
436
437
438
439 protected DataObjectEntry getDataObjectEntry(Class<?> dataObjectClass) {
440 if (dataObjectClass == null) {
441 throw new IllegalArgumentException("invalid (null) dataObjectClass");
442 }
443
444 DataObjectEntry entry = getDataDictionaryService().getDataDictionary().getDataObjectEntry(
445 dataObjectClass.getName());
446
447 return entry;
448 }
449
450 public List<DataObjectRelationship> getDataObjectRelationships(Class<?> dataObjectClass) {
451 if (dataObjectClass == null) {
452 return null;
453 }
454
455 Map<String, Class> referenceClasses = null;
456 if (PersistableBusinessObject.class.isAssignableFrom(dataObjectClass)
457 && getPersistenceStructureService().isPersistable(dataObjectClass)) {
458 referenceClasses = getPersistenceStructureService().listReferenceObjectFields(dataObjectClass);
459 }
460 DataDictionaryEntry ddEntry = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(
461 dataObjectClass.getName());
462 List<RelationshipDefinition> ddRelationships = (ddEntry == null ? new ArrayList<RelationshipDefinition>()
463 : ddEntry.getRelationships());
464 List<DataObjectRelationship> relationships = new ArrayList<DataObjectRelationship>();
465
466
467 if (referenceClasses != null) {
468 for (Map.Entry<String, Class> entry : referenceClasses.entrySet()) {
469 if (classHasSupportedFeatures(entry.getValue(), true, false)) {
470 Map<String, String> fkToPkRefs = getPersistenceStructureService().getForeignKeysForReference(dataObjectClass,
471 entry.getKey());
472 DataObjectRelationship rel = new DataObjectRelationship(dataObjectClass, entry.getKey(),
473 entry.getValue());
474 for (Map.Entry<String, String> ref : fkToPkRefs.entrySet()) {
475 rel.getParentToChildReferences().put(ref.getKey(), ref.getValue());
476 }
477 relationships.add(rel);
478 }
479 }
480 }
481
482 for (RelationshipDefinition rd : ddRelationships) {
483 if (classHasSupportedFeatures(rd.getTargetClass(), true, false)) {
484 DataObjectRelationship rel = new DataObjectRelationship(dataObjectClass, rd.getObjectAttributeName(),
485 rd.getTargetClass());
486 for (PrimitiveAttributeDefinition def : rd.getPrimitiveAttributes()) {
487 rel.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
488 }
489 relationships.add(rel);
490 }
491 }
492
493 return relationships;
494 }
495
496
497
498
499
500
501 protected BusinessObjectEntry getBusinessObjectEntry(Class businessObjectClass) {
502 validateBusinessObjectClass(businessObjectClass);
503
504 BusinessObjectEntry entry = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(
505 businessObjectClass.getName());
506 return entry;
507 }
508
509
510
511
512
513 protected void validateBusinessObjectClass(Class businessObjectClass) {
514 if (businessObjectClass == null) {
515 throw new IllegalArgumentException("invalid (null) dataObjectClass");
516 }
517 if (!BusinessObject.class.isAssignableFrom(businessObjectClass)) {
518 throw new IllegalArgumentException(
519 "class '" + businessObjectClass.getName() + "' is not a descendant of BusinessObject");
520 }
521 }
522
523
524
525
526
527
528 protected DataDictionaryService getDataDictionaryService() {
529 return this.dataDictionaryService;
530 }
531
532 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
533 this.dataDictionaryService = dataDictionaryService;
534 }
535
536
537
538
539
540
541 protected KualiModuleService getKualiModuleService() {
542 return this.kualiModuleService;
543 }
544
545 public void setKualiModuleService(KualiModuleService kualiModuleService) {
546 this.kualiModuleService = kualiModuleService;
547 }
548
549
550
551
552
553
554
555 protected PersistenceStructureService getPersistenceStructureService() {
556 return this.persistenceStructureService;
557 }
558
559 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
560 this.persistenceStructureService = persistenceStructureService;
561 }
562
563 protected ViewDictionaryService getViewDictionaryService() {
564 if (this.viewDictionaryService == null) {
565 this.viewDictionaryService = KRADServiceLocatorWeb.getViewDictionaryService();
566 }
567 return this.viewDictionaryService;
568 }
569
570 public void setViewDictionaryService(ViewDictionaryService viewDictionaryService) {
571 this.viewDictionaryService = viewDictionaryService;
572 }
573
574 }