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