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