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