1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kns.service.impl;
17
18 import java.beans.PropertyDescriptor;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.commons.beanutils.PropertyUtils;
30 import org.apache.commons.lang.StringUtils;
31 import org.kuali.rice.core.config.ConfigContext;
32 import org.kuali.rice.kim.bo.Person;
33 import org.kuali.rice.kim.service.KIMServiceLocator;
34 import org.kuali.rice.kim.service.PersonService;
35 import org.kuali.rice.kns.bo.BusinessObject;
36 import org.kuali.rice.kns.bo.BusinessObjectRelationship;
37 import org.kuali.rice.kns.bo.ExternalizableBusinessObject;
38 import org.kuali.rice.kns.bo.PersistableBusinessObject;
39 import org.kuali.rice.kns.dao.BusinessObjectDao;
40 import org.kuali.rice.kns.exception.ObjectNotABusinessObjectRuntimeException;
41 import org.kuali.rice.kns.exception.ReferenceAttributeDoesntExistException;
42 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
43 import org.kuali.rice.kns.service.BusinessObjectService;
44 import org.kuali.rice.kns.service.KNSServiceLocator;
45 import org.kuali.rice.kns.service.ModuleService;
46 import org.kuali.rice.kns.service.PersistenceService;
47 import org.kuali.rice.kns.service.PersistenceStructureService;
48 import org.kuali.rice.kns.util.KNSConstants;
49 import org.kuali.rice.kns.util.ObjectUtils;
50 import org.springframework.transaction.annotation.Transactional;
51
52
53
54
55
56
57 public class BusinessObjectServiceImpl implements BusinessObjectService {
58
59 private PersistenceService persistenceService;
60 private PersistenceStructureService persistenceStructureService;
61 private BusinessObjectDao businessObjectDao;
62 private PersonService personService;
63 private BusinessObjectMetaDataService businessObjectMetaDataService;
64
65 private boolean illegalBusinessObjectsForSaveInitialized = false;
66 private Set<String> illegalBusinessObjectsForSave = new HashSet<String>();
67
68
69
70
71 @Transactional
72 public void save(PersistableBusinessObject bo) {
73 validateBusinessObjectForSave(bo);
74 businessObjectDao.save(bo);
75 }
76
77
78
79
80 @Transactional
81 public void save(List<? extends PersistableBusinessObject> businessObjects) {
82 validateBusinessObjectForSave(businessObjects);
83 businessObjectDao.save(businessObjects);
84 }
85
86
87
88
89
90 @Transactional
91 public void linkAndSave(PersistableBusinessObject bo) {
92 validateBusinessObjectForSave(bo);
93 persistenceService.linkObjects(bo);
94 businessObjectDao.save(bo);
95 }
96
97
98
99
100
101 @Transactional
102 public void linkAndSave(List<? extends PersistableBusinessObject> businessObjects) {
103 validateBusinessObjectForSave(businessObjects);
104 businessObjectDao.save(businessObjects);
105 }
106
107
108
109
110
111
112
113 protected void validateBusinessObjectForSave(PersistableBusinessObject bo) {
114 if (bo == null) {
115 throw new IllegalArgumentException("Object passed in is null");
116 }
117 if (!isBusinessObjectAllowedForSave(bo)) {
118 throw new IllegalArgumentException("Object passed in is a BusinessObject but has been restricted from save operations according to configuration parameter '" + KNSConstants.Config.ILLEGAL_BUSINESS_OBJECTS_FOR_SAVE);
119 }
120 }
121
122 protected void validateBusinessObjectForSave(List<? extends PersistableBusinessObject> businessObjects) {
123 for (PersistableBusinessObject bo : businessObjects) {
124 if (bo == null) {
125 throw new IllegalArgumentException("One of the objects in the List is null.");
126 }
127 if (!isBusinessObjectAllowedForSave(bo)) {
128 throw new IllegalArgumentException("One of the objects in the List is a BusinessObject but has been restricted from save operations according to configuration parameter '" + KNSConstants.Config.ILLEGAL_BUSINESS_OBJECTS_FOR_SAVE
129 + " Passed in type was '" + bo.getClass().getName() + "'.");
130 }
131 }
132 }
133
134
135
136
137
138
139
140 protected boolean isBusinessObjectAllowedForSave(PersistableBusinessObject bo) {
141 if (!illegalBusinessObjectsForSaveInitialized) {
142 synchronized (this) {
143 boolean applyCheck = true;
144 String applyCheckValue = ConfigContext.getCurrentContextConfig().getProperty(KNSConstants.Config.APPLY_ILLEGAL_BUSINESS_OBJECT_FOR_SAVE_CHECK);
145 if (!StringUtils.isEmpty(applyCheckValue)) {
146 applyCheck = new Boolean(applyCheckValue);
147 }
148 if (applyCheck) {
149 String illegalBos = ConfigContext.getCurrentContextConfig().getProperty(KNSConstants.Config.ILLEGAL_BUSINESS_OBJECTS_FOR_SAVE);
150 if (!StringUtils.isEmpty(illegalBos)) {
151 String[] illegalBosSplit = illegalBos.split(",");
152 for (String illegalBo : illegalBosSplit) {
153 illegalBusinessObjectsForSave.add(illegalBo.trim());
154 }
155 }
156 }
157 }
158 illegalBusinessObjectsForSaveInitialized = true;
159 }
160 return !illegalBusinessObjectsForSave.contains(bo.getClass().getName());
161 }
162
163
164
165
166 @SuppressWarnings("unchecked")
167 public <T> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey) {
168 return (T)businessObjectDao.findBySinglePrimaryKey(clazz, primaryKey);
169 }
170
171
172
173
174 public PersistableBusinessObject findByPrimaryKey(Class clazz, Map primaryKeys) {
175 return businessObjectDao.findByPrimaryKey(clazz, primaryKeys);
176 }
177
178
179
180
181 public PersistableBusinessObject retrieve(PersistableBusinessObject object) {
182 return businessObjectDao.retrieve(object);
183 }
184
185
186
187
188 public Collection findAll(Class clazz) {
189 Collection coll = businessObjectDao.findAll(clazz);
190 return new ArrayList(coll);
191 }
192
193
194
195
196 public Collection findMatching(Class clazz, Map fieldValues) {
197 return new ArrayList(businessObjectDao.findMatching(clazz, fieldValues));
198 }
199
200
201
202
203 public int countMatching(Class clazz, Map fieldValues) {
204 return businessObjectDao.countMatching(clazz, fieldValues);
205 }
206
207
208
209
210 public int countMatching(Class clazz, Map positiveFieldValues, Map negativeFieldValues) {
211 return businessObjectDao.countMatching(clazz, positiveFieldValues, negativeFieldValues);
212 }
213
214
215
216
217 public Collection findMatchingOrderBy(Class clazz, Map fieldValues, String sortField, boolean sortAscending) {
218 return new ArrayList(businessObjectDao.findMatchingOrderBy(clazz, fieldValues, sortField, sortAscending));
219 }
220
221
222
223
224 @Transactional
225 public void delete(PersistableBusinessObject bo) {
226 businessObjectDao.delete(bo);
227 }
228
229
230
231
232 @Transactional
233 public void delete(List<? extends PersistableBusinessObject> boList) {
234 businessObjectDao.delete(boList);
235 }
236
237
238
239
240
241 @Transactional
242 public void deleteMatching(Class clazz, Map fieldValues) {
243 businessObjectDao.deleteMatching(clazz, fieldValues);
244 }
245
246
247
248
249 public BusinessObject getReferenceIfExists(BusinessObject bo, String referenceName) {
250
251 PersistableBusinessObject referenceBo = null;
252 boolean allFkeysHaveValues = true;
253
254
255 if (ObjectUtils.isNull(bo)) {
256 throw new IllegalArgumentException("Passed in BusinessObject was null. No processing can be done.");
257 }
258 if (StringUtils.isEmpty(referenceName)) {
259 throw new IllegalArgumentException("Passed in referenceName was empty or null. No processing can be done.");
260 }
261
262
263 PropertyDescriptor propertyDescriptor;
264 try {
265 propertyDescriptor = PropertyUtils.getPropertyDescriptor(bo, referenceName);
266 }
267 catch (Exception e) {
268 throw new RuntimeException(e);
269 }
270 if (propertyDescriptor == null) {
271 throw new ReferenceAttributeDoesntExistException("Requested attribute: '" + referenceName + "' does not exist " + "on class: '" + bo.getClass().getName() + "'. GFK");
272 }
273
274
275 Class referenceClass = ObjectUtils.getPropertyType( bo, referenceName, persistenceStructureService );
276 if ( referenceClass == null ) {
277 referenceClass = propertyDescriptor.getPropertyType();
278 }
279
280
281
282
283 if (ExternalizableBusinessObject.class.isAssignableFrom(referenceClass)) {
284 try {
285 BusinessObject referenceBoExternalizable = (BusinessObject) PropertyUtils.getProperty(bo, referenceName);
286 if(referenceBoExternalizable!=null)
287 return referenceBoExternalizable;
288 } catch (Exception ex) {
289
290
291 }
292 }
293
294
295
296 if (!ExternalizableBusinessObject.class.isAssignableFrom(referenceClass) && !PersistableBusinessObject.class.isAssignableFrom(referenceClass)) {
297 throw new ObjectNotABusinessObjectRuntimeException("Attribute requested (" + referenceName + ") is of class: " + "'" + referenceClass.getName() + "' and is not a " + "descendent of PersistableBusinessObject. Only descendents of PersistableBusinessObject " + "can be used.");
298 }
299
300
301
302
303 BusinessObjectRelationship boRel = businessObjectMetaDataService.getBusinessObjectRelationship( bo, referenceName );
304 Map<String,String> fkMap = null;
305 if ( boRel != null ) {
306 fkMap = boRel.getParentToChildReferences();
307 } else {
308 fkMap = Collections.EMPTY_MAP;
309 }
310
311
312 Map pkMap = new HashMap();
313 for (Iterator iter = fkMap.keySet().iterator(); iter.hasNext();) {
314 String fkFieldName = (String) iter.next();
315 String pkFieldName = (String) fkMap.get(fkFieldName);
316
317
318 Object fkFieldValue;
319 try {
320 fkFieldValue = PropertyUtils.getProperty(bo, fkFieldName);
321 }
322 catch (Exception e) {
323 throw new RuntimeException(e);
324 }
325
326
327 if (ObjectUtils.isNull(fkFieldValue)) {
328 allFkeysHaveValues = false;
329 break;
330 }
331 else if (String.class.isAssignableFrom(fkFieldValue.getClass())) {
332 if (StringUtils.isEmpty((String) fkFieldValue)) {
333 allFkeysHaveValues = false;
334 break;
335 }
336 else {
337 pkMap.put(pkFieldName, fkFieldValue);
338 }
339 }
340
341
342 else {
343 pkMap.put(pkFieldName, fkFieldValue);
344 }
345 }
346
347
348 if (allFkeysHaveValues) {
349 if (ExternalizableBusinessObject.class.isAssignableFrom(referenceClass)) {
350 ModuleService responsibleModuleService = KNSServiceLocator.getKualiModuleService().getResponsibleModuleService(referenceClass);
351 if(responsibleModuleService!=null) {
352 return (BusinessObject)responsibleModuleService.getExternalizableBusinessObject(referenceClass, pkMap);
353 }
354 } else
355 referenceBo = findByPrimaryKey(referenceClass, pkMap);
356 }
357
358
359 return referenceBo;
360 }
361
362
363
364
365
366 public void linkUserFields(PersistableBusinessObject bo) {
367 if (bo == null) {
368 throw new IllegalArgumentException("bo passed in was null");
369 }
370
371 bo.linkEditableUserFields();
372
373 linkUserFields( Collections.singletonList( bo ) );
374 }
375
376
377
378
379
380 public void linkUserFields(List<PersistableBusinessObject> bos) {
381
382
383 if (bos == null) {
384 throw new IllegalArgumentException("List of bos passed in was null");
385 }
386 else if (bos.isEmpty()) {
387 return;
388 }
389
390 Person person = null;
391
392 for (PersistableBusinessObject bo : bos) {
393
394 List<BusinessObjectRelationship> relationships = businessObjectMetaDataService.getBusinessObjectRelationships( bo );
395 for ( BusinessObjectRelationship rel : relationships ) {
396 if ( Person.class.isAssignableFrom( rel.getRelatedClass() ) ) {
397 person = (Person) ObjectUtils.getPropertyValue(bo, rel.getParentAttributeName() );
398 if (person != null) {
399
400 for ( Map.Entry<String,String> entry : rel.getParentToChildReferences().entrySet() ) {
401 if ( entry.getValue().equals( "principalId" ) ) {
402 linkUserReference(bo, person, rel.getParentAttributeName(), entry.getKey() );
403 break;
404 }
405 }
406 }
407 }
408 }
409 if ( persistenceStructureService.isPersistable(bo.getClass())) {
410 Map<String, Class> references = persistenceStructureService.listReferenceObjectFields(bo);
411
412
413 for ( String refField : references.keySet() ) {
414 Class<?> refClass = references.get(refField);
415 if (Person.class.isAssignableFrom(refClass)) {
416 person = (Person) ObjectUtils.getPropertyValue(bo, refField);
417 if (person != null) {
418 String fkFieldName = persistenceStructureService.getForeignKeyFieldName(bo.getClass(), refField, "principalId");
419 linkUserReference(bo, person, refField, fkFieldName);
420 }
421 }
422 }
423 }
424 }
425 }
426
427
428
429
430
431
432
433
434
435 private void linkUserReference(PersistableBusinessObject bo, Person user, String refFieldName, String fkFieldName) {
436
437
438 if (StringUtils.isBlank(user.getPrincipalName())) {
439 return;
440 }
441
442
443 Person userFromService = getPersonService().getPersonByPrincipalName(user.getPrincipalName());
444 if (userFromService == null) {
445 return;
446 }
447
448
449 setBoField(bo, fkFieldName, userFromService.getPrincipalId());
450 }
451
452 private void setBoField(PersistableBusinessObject bo, String fieldName, Object fieldValue) {
453 try {
454 ObjectUtils.setObjectProperty(bo, fieldName, fieldValue.getClass(), fieldValue);
455 }
456 catch (Exception e) {
457 throw new RuntimeException("Could not set field [" + fieldName + "] on BO to value: " + fieldValue.toString() + " (see nested exception for details).", e);
458 }
459 }
460
461
462
463
464
465
466 protected BusinessObjectDao getBusinessObjectDao() {
467 return businessObjectDao;
468 }
469
470
471
472
473
474
475 public void setBusinessObjectDao(BusinessObjectDao businessObjectDao) {
476 this.businessObjectDao = businessObjectDao;
477 }
478
479
480
481
482
483
484 public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
485 this.persistenceStructureService = persistenceStructureService;
486 }
487
488
489
490
491 @SuppressWarnings("unchecked")
492 public final void setPersonService(PersonService personService) {
493 this.personService = personService;
494 }
495
496 @SuppressWarnings("unchecked")
497 protected PersonService getPersonService() {
498 return personService != null ? personService : (personService = KIMServiceLocator.getPersonService());
499 }
500
501
502
503
504
505
506 public final void setPersistenceService(PersistenceService persistenceService) {
507 this.persistenceService = persistenceService;
508 }
509
510 protected BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
511 return businessObjectMetaDataService;
512 }
513
514 public void setBusinessObjectMetaDataService(BusinessObjectMetaDataService boMetadataService) {
515 this.businessObjectMetaDataService = boMetadataService;
516 }
517
518 }