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.kuali.rice.krad.web.controller.UifControllerBase;
47 import org.springframework.beans.BeanWrapper;
48
49
50
51
52 public class DataObjectMetaDataServiceImpl implements DataObjectMetaDataService {
53
54 private DataDictionaryService dataDictionaryService;
55 private KualiModuleService kualiModuleService;
56 private PersistenceStructureService persistenceStructureService;
57 private ViewDictionaryService viewDictionaryService;
58
59
60
61
62 @Override
63 public List<String> listPrimaryKeyFieldNames(Class<?> clazz) {
64 if (persistenceStructureService.isPersistable(clazz)) {
65 return persistenceStructureService.listPrimaryKeyFieldNames(clazz);
66 }
67
68 ModuleService responsibleModuleService = getKualiModuleService().getResponsibleModuleService(clazz);
69 if (responsibleModuleService != null && responsibleModuleService.isExternalizable(clazz)) {
70 return responsibleModuleService.listPrimaryKeyFieldNames(clazz);
71 }
72
73
74 List<String> pks = dataDictionaryService.getDataDictionary().getDataObjectEntry(clazz.getName())
75 .getPrimaryKeys();
76 if (pks != null && !pks.isEmpty()) {
77 return pks;
78 }
79
80 return new ArrayList<String>();
81 }
82
83
84
85
86 @Override
87 public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject) {
88 return getPrimaryKeyFieldValues(dataObject, false);
89 }
90
91
92
93
94
95 @Override
96 public Map<String, ?> getPrimaryKeyFieldValues(Object dataObject, boolean sortFieldNames) {
97 Map<String, Object> keyValueMap;
98
99 if (sortFieldNames) {
100 keyValueMap = new TreeMap<String, Object>();
101 } else {
102 keyValueMap = new HashMap<String, Object>();
103 }
104
105 BeanWrapper wrapper = ObjectPropertyUtils.wrapObject(dataObject);
106
107 List<String> fields = listPrimaryKeyFieldNames(dataObject.getClass());
108 for (String fieldName : fields) {
109 keyValueMap.put(fieldName, wrapper.getPropertyValue(fieldName));
110 }
111
112 return keyValueMap;
113 }
114
115
116
117
118
119 @Override
120 public boolean equalsByPrimaryKeys(Object do1, Object do2) {
121 boolean equal = true;
122
123 if (do1 == null && do2 == null) {
124 equal = true;
125 } else if (do1 == null || do2 == null) {
126 equal = false;
127 } else if (!do1.getClass().getName().equals(do2.getClass().getName())) {
128 equal = false;
129 } else {
130 Map<String, ?> do1Keys = getPrimaryKeyFieldValues(do1);
131 Map<String, ?> do2Keys = getPrimaryKeyFieldValues(do2);
132 for (Iterator<String> iter = do1Keys.keySet().iterator(); iter.hasNext(); ) {
133 String keyName = iter.next();
134 if (do1Keys.get(keyName) != null && do2Keys.get(keyName) != null) {
135 if (!do1Keys.get(keyName).toString().equals(do2Keys.get(keyName).toString())) {
136 equal = false;
137 }
138 } else {
139 equal = false;
140 }
141 }
142 }
143
144 return equal;
145 }
146
147
148
149
150
151
152 public DataObjectRelationship getDataObjectRelationship(Object dataObject, Class<?> dataObjectClass,
153 String attributeName, String attributePrefix, boolean keysOnly, boolean supportsLookup,
154 boolean supportsInquiry) {
155 RelationshipDefinition ddReference = getDictionaryRelationship(dataObjectClass, attributeName);
156
157 return getDataObjectRelationship(ddReference, dataObject, dataObjectClass, attributeName, attributePrefix,
158 keysOnly, supportsLookup, supportsInquiry);
159 }
160
161 protected DataObjectRelationship getDataObjectRelationship(RelationshipDefinition ddReference, Object dataObject,
162 Class<?> dataObjectClass, String attributeName, String attributePrefix, boolean keysOnly,
163 boolean supportsLookup, boolean supportsInquiry) {
164 DataObjectRelationship relationship = null;
165
166
167
168 if (ObjectUtils.isNestedAttribute(attributeName)) {
169 if (ddReference != null) {
170 if (classHasSupportedFeatures(ddReference.getTargetClass(), supportsLookup, supportsInquiry)) {
171 relationship = populateRelationshipFromDictionaryReference(dataObjectClass, ddReference,
172 attributePrefix, keysOnly);
173
174 return relationship;
175 }
176 }
177
178
179 String localPrefix = StringUtils.substringBefore(attributeName, ".");
180 String localAttributeName = StringUtils.substringAfter(attributeName, ".");
181 if (dataObject == null) {
182 dataObject = ObjectUtils.createNewObjectFromClass(dataObjectClass);
183 }
184
185 Object nestedObject = ObjectPropertyUtils.getPropertyValue(dataObject, localPrefix);
186 Class<?> nestedClass = null;
187 if (nestedObject == null) {
188 nestedClass = ObjectPropertyUtils.getPropertyType(dataObject, localPrefix);
189 } else {
190 nestedClass = nestedObject.getClass();
191 }
192
193 String fullPrefix = localPrefix;
194 if (StringUtils.isNotBlank(attributePrefix)) {
195 fullPrefix = attributePrefix + "." + localPrefix;
196 }
197
198 relationship = getDataObjectRelationship(nestedObject, nestedClass, localAttributeName, fullPrefix,
199 keysOnly, supportsLookup, supportsInquiry);
200
201 return relationship;
202 }
203
204
205 int maxSize = Integer.MAX_VALUE;
206
207
208 if (getPersistenceStructureService().isPersistable(dataObjectClass)) {
209 Map<String, DataObjectRelationship> rels = getPersistenceStructureService().getRelationshipMetadata(
210 dataObjectClass, attributeName, attributePrefix);
211 if (rels.size() > 0) {
212 for (DataObjectRelationship rel : rels.values()) {
213 if (rel.getParentToChildReferences().size() < maxSize) {
214 if (classHasSupportedFeatures(rel.getRelatedClass(), supportsLookup, supportsInquiry)) {
215 maxSize = rel.getParentToChildReferences().size();
216 relationship = rel;
217 }
218 }
219 }
220 }
221 } else {
222 ModuleService moduleService = getKualiModuleService().getResponsibleModuleService(dataObjectClass);
223 if (moduleService != null && moduleService.isExternalizable(dataObjectClass)) {
224 relationship = getRelationshipMetadata(dataObjectClass, attributeName, attributePrefix);
225 if ((relationship != null) && classHasSupportedFeatures(relationship.getRelatedClass(), supportsLookup,
226 supportsInquiry)) {
227 return relationship;
228 } else {
229 return null;
230 }
231 }
232 }
233
234 if (ddReference != null && ddReference.getPrimitiveAttributes().size() < maxSize) {
235 if (classHasSupportedFeatures(ddReference.getTargetClass(), supportsLookup, supportsInquiry)) {
236 relationship = populateRelationshipFromDictionaryReference(dataObjectClass, ddReference, null,
237 keysOnly);
238 }
239 }
240
241 return relationship;
242 }
243
244 protected boolean classHasSupportedFeatures(Class relationshipClass, boolean supportsLookup,
245 boolean supportsInquiry) {
246 boolean hasSupportedFeatures = true;
247 if (supportsLookup && !getViewDictionaryService().isLookupable(relationshipClass)) {
248 hasSupportedFeatures = false;
249 }
250 if (supportsInquiry && !getViewDictionaryService().isInquirable(relationshipClass)) {
251 hasSupportedFeatures = false;
252 }
253
254 return hasSupportedFeatures;
255 }
256
257 public RelationshipDefinition getDictionaryRelationship(Class<?> c, String attributeName) {
258 DataDictionaryEntry entryBase = getDataDictionaryService().getDataDictionary().getDictionaryObjectEntry(
259 c.getName());
260 if (entryBase == null) {
261 return null;
262 }
263
264 RelationshipDefinition relationship = null;
265
266 List<RelationshipDefinition> ddRelationships = entryBase.getRelationships();
267
268 int minKeys = Integer.MAX_VALUE;
269 for (RelationshipDefinition def : ddRelationships) {
270
271 if (def.getPrimitiveAttributes().size() == 1) {
272 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
273 if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
274 attributeName)) {
275 relationship = def;
276 minKeys = 1;
277 break;
278 }
279 }
280 } else if (def.getPrimitiveAttributes().size() < minKeys) {
281 for (PrimitiveAttributeDefinition primitive : def.getPrimitiveAttributes()) {
282 if (primitive.getSourceName().equals(attributeName) || def.getObjectAttributeName().equals(
283 attributeName)) {
284 relationship = def;
285 minKeys = def.getPrimitiveAttributes().size();
286 break;
287 }
288 }
289 }
290 }
291
292
293 if (relationship == null) {
294 for (RelationshipDefinition def : ddRelationships) {
295 if (def.hasIdentifier()) {
296 if (def.getIdentifier().getSourceName().equals(attributeName)) {
297 relationship = def;
298 }
299 }
300 }
301 }
302
303 return relationship;
304 }
305
306 protected DataObjectRelationship populateRelationshipFromDictionaryReference(Class<?> dataObjectClass,
307 RelationshipDefinition ddReference, String attributePrefix, boolean keysOnly) {
308 DataObjectRelationship relationship = new DataObjectRelationship(dataObjectClass,
309 ddReference.getObjectAttributeName(), ddReference.getTargetClass());
310
311 for (PrimitiveAttributeDefinition def : ddReference.getPrimitiveAttributes()) {
312 if (StringUtils.isNotBlank(attributePrefix)) {
313 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
314 def.getTargetName());
315 } else {
316 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
317 }
318 }
319
320 if (!keysOnly) {
321 for (SupportAttributeDefinition def : ddReference.getSupportAttributes()) {
322 if (StringUtils.isNotBlank(attributePrefix)) {
323 relationship.getParentToChildReferences().put(attributePrefix + "." + def.getSourceName(),
324 def.getTargetName());
325 if (def.isIdentifier()) {
326 relationship.setUserVisibleIdentifierKey(attributePrefix + "." + def.getSourceName());
327 }
328 } else {
329 relationship.getParentToChildReferences().put(def.getSourceName(), def.getTargetName());
330 if (def.isIdentifier()) {
331 relationship.setUserVisibleIdentifierKey(def.getSourceName());
332 }
333 }
334 }
335 }
336
337 return relationship;
338 }
339
340 protected DataObjectRelationship getRelationshipMetadata(Class<?> dataObjectClass, String attributeName,
341 String attributePrefix) {
342
343 RelationshipDefinition relationshipDefinition = getDictionaryRelationship(dataObjectClass, attributeName);
344 if (relationshipDefinition == null) {
345 return null;
346 }
347
348 DataObjectRelationship dataObjectRelationship = new DataObjectRelationship(
349 relationshipDefinition.getSourceClass(), relationshipDefinition.getObjectAttributeName(),
350 relationshipDefinition.getTargetClass());
351
352 if (!StringUtils.isEmpty(attributePrefix)) {
353 attributePrefix += ".";
354 }
355
356 List<PrimitiveAttributeDefinition> primitives = relationshipDefinition.getPrimitiveAttributes();
357 for (PrimitiveAttributeDefinition primitiveAttributeDefinition : primitives) {
358 dataObjectRelationship.getParentToChildReferences().put(
359 attributePrefix + primitiveAttributeDefinition.getSourceName(),
360 primitiveAttributeDefinition.getTargetName());
361 }
362
363 return dataObjectRelationship;
364 }
365
366
367
368
369 public String getTitleAttribute(Class<?> dataObjectClass) {
370 String titleAttribute = null;
371
372 DataObjectEntry entry = getDataObjectEntry(dataObjectClass);
373 if (entry != null) {
374 titleAttribute = entry.getTitleAttribute();
375 }
376
377 return titleAttribute;
378 }
379
380
381
382
383 public boolean areNotesSupported(Class dataObjectClass) {
384 boolean hasNotesSupport = false;
385
386 DataObjectEntry entry = getDataObjectEntry(UifControllerBase.class);
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
451
452
453
454
455 protected BusinessObjectEntry getBusinessObjectEntry(Class businessObjectClass) {
456 validateBusinessObjectClass(businessObjectClass);
457
458 BusinessObjectEntry entry = getDataDictionaryService().getDataDictionary().getBusinessObjectEntry(
459 businessObjectClass.getName());
460 return entry;
461 }
462
463
464
465
466
467 protected void validateBusinessObjectClass(Class businessObjectClass) {
468 if (businessObjectClass == null) {
469 throw new IllegalArgumentException("invalid (null) dataObjectClass");
470 }
471 if (!BusinessObject.class.isAssignableFrom(businessObjectClass)) {
472 throw new IllegalArgumentException(
473 "class '" + businessObjectClass.getName() + "' is not a descendant of BusinessObject");
474 }
475 }
476
477
478
479
480
481
482 protected DataDictionaryService getDataDictionaryService() {
483 return this.dataDictionaryService;
484 }
485
486 public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
487 this.dataDictionaryService = dataDictionaryService;
488 }
489
490
491
492
493
494
495 protected KualiModuleService getKualiModuleService() {
496 return this.kualiModuleService;
497 }
498
499 public void setKualiModuleService(KualiModuleService kualiModuleService) {
500 this.kualiModuleService = kualiModuleService;
501 }
502
503
504
505
506
507
508
509 protected PersistenceStructureService getPersistenceStructureService() {
510 return this.persistenceStructureService;
511 }
512
513 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
514 this.persistenceStructureService = persistenceStructureService;
515 }
516
517 protected ViewDictionaryService getViewDictionaryService() {
518 if (this.viewDictionaryService == null) {
519 this.viewDictionaryService = KRADServiceLocatorWeb.getViewDictionaryService();
520 }
521 return this.viewDictionaryService;
522 }
523
524 public void setViewDictionaryService(ViewDictionaryService viewDictionaryService) {
525 this.viewDictionaryService = viewDictionaryService;
526 }
527
528 }