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