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