001 /**
002 * Copyright 2005-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kns.maintenance;
017
018 import org.apache.commons.beanutils.PropertyUtils;
019 import org.apache.commons.lang.StringUtils;
020 import org.kuali.rice.core.api.CoreApiServiceLocator;
021 import org.kuali.rice.core.api.encryption.EncryptionService;
022 import org.kuali.rice.core.web.format.FormatException;
023 import org.kuali.rice.kim.api.identity.PersonService;
024 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
025 import org.kuali.rice.kns.datadictionary.MaintainableCollectionDefinition;
026 import org.kuali.rice.kns.datadictionary.MaintainableFieldDefinition;
027 import org.kuali.rice.kns.datadictionary.MaintainableItemDefinition;
028 import org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition;
029 import org.kuali.rice.kns.document.MaintenanceDocument;
030 import org.kuali.rice.kns.document.authorization.FieldRestriction;
031 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentPresentationController;
032 import org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions;
033 import org.kuali.rice.kns.lookup.LookupUtils;
034 import org.kuali.rice.kns.service.BusinessObjectAuthorizationService;
035 import org.kuali.rice.kns.service.BusinessObjectDictionaryService;
036 import org.kuali.rice.kns.service.BusinessObjectMetaDataService;
037 import org.kuali.rice.kns.service.DocumentHelperService;
038 import org.kuali.rice.kns.service.KNSServiceLocator;
039 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService;
040 import org.kuali.rice.kns.util.FieldUtils;
041 import org.kuali.rice.kns.util.InactiveRecordsHidingUtils;
042 import org.kuali.rice.kns.util.MaintenanceUtils;
043 import org.kuali.rice.kns.web.ui.Section;
044 import org.kuali.rice.kns.web.ui.SectionBridge;
045 import org.kuali.rice.krad.bo.BusinessObject;
046 import org.kuali.rice.krad.bo.DataObjectRelationship;
047 import org.kuali.rice.krad.bo.PersistableBusinessObject;
048 import org.kuali.rice.krad.datadictionary.AttributeSecurity;
049 import org.kuali.rice.krad.datadictionary.exception.UnknownBusinessClassAttributeException;
050 import org.kuali.rice.krad.maintenance.MaintainableImpl;
051 import org.kuali.rice.krad.service.DataDictionaryService;
052 import org.kuali.rice.krad.service.KRADServiceLocator;
053 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
054 import org.kuali.rice.krad.service.ModuleService;
055 import org.kuali.rice.krad.service.PersistenceStructureService;
056 import org.kuali.rice.krad.util.GlobalVariables;
057 import org.kuali.rice.krad.util.KRADConstants;
058 import org.kuali.rice.krad.util.KRADPropertyConstants;
059 import org.kuali.rice.krad.util.MessageMap;
060 import org.kuali.rice.krad.util.ObjectUtils;
061 import org.kuali.rice.krad.valuefinder.ValueFinder;
062
063 import java.beans.PropertyDescriptor;
064 import java.lang.reflect.InvocationTargetException;
065 import java.security.GeneralSecurityException;
066 import java.util.ArrayList;
067 import java.util.Collection;
068 import java.util.HashMap;
069 import java.util.HashSet;
070 import java.util.Iterator;
071 import java.util.List;
072 import java.util.Map;
073 import java.util.Set;
074
075 /**
076 * Base Maintainable class to hold things common to all maintainables.
077 */
078 @Deprecated
079 public class KualiMaintainableImpl extends MaintainableImpl implements Maintainable {
080 private static final long serialVersionUID = 4814145799502207182L;
081
082 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiMaintainableImpl.class);
083
084 protected PersistableBusinessObject businessObject;
085
086 protected Map<String, PersistableBusinessObject> newCollectionLines = new HashMap<String, PersistableBusinessObject>();
087 protected Map<String, Boolean> inactiveRecordDisplay = new HashMap<String, Boolean>();
088
089 // TODO: rename once 'newCollectionLines' is removed
090 protected Set<String> newCollectionLineNames = new HashSet<String>();
091
092 protected transient BusinessObjectDictionaryService businessObjectDictionaryService;
093 protected transient PersonService personService;
094 protected transient BusinessObjectMetaDataService businessObjectMetaDataService;
095 protected transient BusinessObjectAuthorizationService businessObjectAuthorizationService;
096 protected transient DocumentHelperService documentHelperService;
097 protected transient MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
098
099 /**
100 * Default empty constructor
101 */
102 public KualiMaintainableImpl() {
103 super();
104 }
105
106 /**
107 * Constructor which initializes the business object to be maintained.
108 *
109 * @param businessObject
110 */
111 public KualiMaintainableImpl(PersistableBusinessObject businessObject) {
112 super();
113 this.businessObject = businessObject;
114 super.setDataObject(businessObject);
115 }
116
117 /**
118 * @see Maintainable#populateBusinessObject(java.util.Map,
119 * org.kuali.rice.krad.maintenance.MaintenanceDocument, String)
120 */
121 @SuppressWarnings("unchecked")
122 public Map populateBusinessObject(Map<String, String> fieldValues, MaintenanceDocument maintenanceDocument,
123 String methodToCall) {
124 fieldValues = decryptEncryptedData(fieldValues, maintenanceDocument, methodToCall);
125 Map newFieldValues = null;
126 newFieldValues = getPersonService().resolvePrincipalNamesToPrincipalIds(getBusinessObject(), fieldValues);
127
128 Map cachedValues = FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), newFieldValues);
129 performForceUpperCase(newFieldValues);
130
131 return cachedValues;
132 }
133
134 /**
135 * Special hidden parameters are set on the maintenance jsp starting with a
136 * prefix that tells us which fields have been encrypted. This field finds
137 * the those parameters in the map, whose value gives us the property name
138 * that has an encrypted value. We then need to decrypt the value in the Map
139 * before the business object is populated.
140 *
141 * @param fieldValues
142 * - possibly with encrypted values
143 * @return Map fieldValues - with no encrypted values
144 */
145 protected Map<String, String> decryptEncryptedData(Map<String, String> fieldValues,
146 MaintenanceDocument maintenanceDocument, String methodToCall) {
147 try {
148 MaintenanceDocumentRestrictions auths = KNSServiceLocator.getBusinessObjectAuthorizationService()
149 .getMaintenanceDocumentRestrictions(maintenanceDocument,
150 GlobalVariables.getUserSession().getPerson());
151 for (Iterator<String> iter = fieldValues.keySet().iterator(); iter.hasNext();) {
152 String fieldName = iter.next();
153 String fieldValue = (String) fieldValues.get(fieldName);
154
155 if (fieldValue != null && !"".equals(fieldValue)
156 && fieldValue.endsWith(EncryptionService.ENCRYPTION_POST_PREFIX)) {
157 if (shouldFieldBeEncrypted(maintenanceDocument, fieldName, auths, methodToCall)) {
158 String encryptedValue = fieldValue;
159
160 // take off the postfix
161 encryptedValue = StringUtils.stripEnd(encryptedValue, EncryptionService.ENCRYPTION_POST_PREFIX);
162 if(CoreApiServiceLocator.getEncryptionService().isEnabled()) {
163 String decryptedValue = getEncryptionService().decrypt(encryptedValue);
164
165 fieldValues.put(fieldName, decryptedValue);
166 }
167 }
168 else
169 throw new RuntimeException("The field value for field name " + fieldName
170 + " should not be encrypted.");
171 }
172 else if (fieldValue != null && !"".equals(fieldValue)
173 && auths.hasRestriction(fieldName)
174 && shouldFieldBeEncrypted(maintenanceDocument, fieldName, auths, methodToCall))
175 throw new RuntimeException("The field value for field name " + fieldName + " should be encrypted.");
176 }
177 }
178 catch (GeneralSecurityException e) {
179 throw new RuntimeException("Unable to decrypt secure data: " + e.getMessage());
180 }
181
182 return fieldValues;
183 }
184
185 /**
186 * Determines whether the field in a request should be encrypted. This base
187 * implementation does not work for properties of collection elements.
188 *
189 * This base implementation will only return true if the maintenance
190 * document is being refreshed after a lookup (i.e. methodToCall is
191 * "refresh") and the data dictionary-based attribute security definition
192 * has any restriction defined, whether the user would be authorized to view
193 * the field. This assumes that only fields returned from a lookup should be
194 * encrypted in a request. If the user otherwise has no permissions to
195 * view/edit the field, then a request parameter will not be sent back to
196 * the server for population.
197 *
198 * @param maintenanceDocument
199 * @param fieldName
200 * @param auths
201 * @param methodToCall
202 * @return
203 */
204 protected boolean shouldFieldBeEncrypted(MaintenanceDocument maintenanceDocument, String fieldName,
205 MaintenanceDocumentRestrictions auths, String methodToCall) {
206 if ("refresh".equals(methodToCall) && fieldName != null) {
207 fieldName = fieldName.replaceAll("\\[[0-9]*+\\]", "");
208 fieldName = fieldName.replaceAll("^add\\.", "");
209 Map<String, AttributeSecurity> fieldNameToAttributeSecurityMap = MaintenanceUtils
210 .retrievePropertyPathToAttributeSecurityMappings(getDocumentTypeName());
211 AttributeSecurity attributeSecurity = fieldNameToAttributeSecurityMap.get(fieldName);
212 return attributeSecurity != null && attributeSecurity.hasRestrictionThatRemovesValueFromUI();
213 }
214 else {
215 return false;
216 }
217 }
218
219 /**
220 * Calls method to get all the core sections for the business object defined
221 * in the data dictionary. Then determines if the bo has custom attributes,
222 * if so builds a custom attribute section and adds to the section list.
223 *
224 * @return List of org.kuali.ui.Section objects
225 */
226 public List getSections(MaintenanceDocument document, Maintainable oldMaintainable) {
227 List<Section> sections = new ArrayList<Section>();
228 sections.addAll(getCoreSections(document, oldMaintainable));
229
230 return sections;
231 }
232
233 /**
234 * Gets list of maintenance sections built from the data dictionary. If the
235 * section contains maintenance fields, construct Row/Field UI objects and
236 * place under Section UI. If section contains a maintenance collection,
237 * call method to build a Section UI which contains rows of Container
238 * Fields.
239 *
240 * @return List of org.kuali.ui.Section objects
241 */
242 public List<Section> getCoreSections(MaintenanceDocument document, Maintainable oldMaintainable) {
243 List<Section> sections = new ArrayList<Section>();
244 MaintenanceDocumentRestrictions maintenanceRestrictions = KNSServiceLocator
245 .getBusinessObjectAuthorizationService().getMaintenanceDocumentRestrictions(document,
246 GlobalVariables.getUserSession().getPerson());
247
248 MaintenanceDocumentPresentationController maintenanceDocumentPresentationController = (MaintenanceDocumentPresentationController) getDocumentHelperService()
249 .getDocumentPresentationController(document);
250 Set<String> conditionallyRequiredFields = maintenanceDocumentPresentationController
251 .getConditionallyRequiredPropertyNames(document);
252
253 List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService()
254 .getMaintainableSections(getDocumentTypeName());
255 try {
256 // iterate through section definitions and create Section UI object
257 for (Iterator iter = sectionDefinitions.iterator(); iter.hasNext();) {
258 MaintainableSectionDefinition maintSectionDef = (MaintainableSectionDefinition) iter.next();
259
260 List<String> displayedFieldNames = new ArrayList<String>();
261 if (!maintenanceRestrictions.isHiddenSectionId(maintSectionDef.getId())) {
262
263 for (Iterator iter2 = maintSectionDef.getMaintainableItems().iterator(); iter2.hasNext();) {
264 MaintainableItemDefinition item = (MaintainableItemDefinition) iter2.next();
265 if (item instanceof MaintainableFieldDefinition) {
266 displayedFieldNames.add(((MaintainableFieldDefinition) item).getName());
267 }
268 }
269
270 Section section = SectionBridge
271 .toSection(maintSectionDef, getBusinessObject(), this, oldMaintainable,
272 getMaintenanceAction(), displayedFieldNames, conditionallyRequiredFields);
273 if (maintenanceRestrictions.isReadOnlySectionId(maintSectionDef.getId())) {
274 section.setReadOnly(true);
275 }
276
277 // add to section list
278 sections.add(section);
279 }
280
281 }
282
283 }
284 catch (InstantiationException e) {
285 LOG.error("Unable to create instance of object class" + e.getMessage());
286 throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
287 }
288 catch (IllegalAccessException e) {
289 LOG.error("Unable to create instance of object class" + e.getMessage());
290 throw new RuntimeException("Unable to create instance of object class" + e.getMessage());
291 }
292
293 return sections;
294 }
295
296
297 /**
298 *
299 * @see Maintainable#saveBusinessObject()
300 */
301 public void saveBusinessObject() {
302 getBusinessObjectService().linkAndSave(businessObject);
303 }
304
305 /**
306 * delegate this call to KNS' {@link org.kuali.rice.kns.maintenance.Maintainable#saveBusinessObject()} in order
307 * to support KNS maintainables.
308 */
309 @Override
310 public void saveDataObject() {
311 saveBusinessObject();
312 }
313
314 /**
315 * Retrieves title for maintenance document from data dictionary
316 */
317 public String getMaintainableTitle() {
318 return getMaintenanceDocumentDictionaryService().getMaintenanceLabel(getDocumentTypeName());
319 }
320
321 @Override
322 public void setupNewFromExisting(MaintenanceDocument document, Map<String, String[]> parameters) {
323 }
324
325 public boolean isBoNotesEnabled() {
326 return getDataObjectMetaDataService().areNotesSupported(getDataObjectClass());
327 }
328
329 /**
330 * Overriding to call old (KNS) name of the method
331 */
332 @Override
333 public boolean isNotesEnabled() {
334 return isBoNotesEnabled();
335 }
336
337 /**
338 * @see Maintainable#refresh(java.lang.String,
339 * java.util.Map) Impls will be needed if custom action is needed on
340 * refresh.
341 */
342 public void refresh(String refreshCaller, Map fieldValues, MaintenanceDocument document) {
343 String referencesToRefresh = (String) fieldValues.get(KRADConstants.REFERENCES_TO_REFRESH);
344 refreshReferences(referencesToRefresh);
345 }
346
347 protected void refreshReferences(String referencesToRefresh) {
348 PersistenceStructureService persistenceStructureService = getPersistenceStructureService();
349 if (StringUtils.isNotBlank(referencesToRefresh)) {
350 String[] references = StringUtils.split(referencesToRefresh, KRADConstants.REFERENCES_TO_REFRESH_SEPARATOR);
351 for (String reference : references) {
352 if (StringUtils.isNotBlank(reference)) {
353 if (reference.startsWith(KRADConstants.ADD_PREFIX + ".")) {
354 // add one for the period
355 reference = reference.substring(KRADConstants.ADD_PREFIX.length() + 1);
356
357 String boToRefreshName = StringUtils.substringBeforeLast(reference, ".");
358 String propertyToRefresh = StringUtils.substringAfterLast(reference, ".");
359 if (StringUtils.isNotBlank(propertyToRefresh)) {
360 PersistableBusinessObject addlineBO = getNewCollectionLine(boToRefreshName);
361 Class addlineBOClass = addlineBO.getClass();
362 if (LOG.isDebugEnabled()) {
363 LOG.debug("Refresh this \"new\"/add object for the collections: " + reference);
364 }
365 if (persistenceStructureService.hasReference(addlineBOClass, propertyToRefresh)
366 || persistenceStructureService.hasCollection(addlineBOClass, propertyToRefresh)) {
367 addlineBO.refreshReferenceObject(propertyToRefresh);
368 }
369 else {
370 if (getDataDictionaryService().hasRelationship(addlineBOClass.getName(),
371 propertyToRefresh)) {
372 // a DD mapping, try to go straight to the
373 // object and refresh it there
374 Object possibleBO = ObjectUtils.getPropertyValue(addlineBO, propertyToRefresh);
375 if (possibleBO != null && possibleBO instanceof PersistableBusinessObject) {
376 ((PersistableBusinessObject) possibleBO).refresh();
377 }
378 }
379 }
380 }
381 else {
382 LOG.error("Error: unable to refresh this \"new\"/add object for the collections: "
383 + reference);
384 }
385 }
386 else if (ObjectUtils.isNestedAttribute(reference)) {
387 Object nestedObject = ObjectUtils.getNestedValue(getBusinessObject(),
388 ObjectUtils.getNestedAttributePrefix(reference));
389 if (nestedObject == null) {
390 LOG.warn("Unable to refresh ReferenceToRefresh (" + reference + ") was found to be null");
391 }
392 else {
393 if (nestedObject instanceof Collection) {
394 // do nothing, probably because it's not really a
395 // collection reference but a relationship defined
396 // in the DD for a collections lookup
397 // this part will need to be rewritten when the DD
398 // supports true collection references
399 }
400 else if (nestedObject instanceof PersistableBusinessObject) {
401 String propertyToRefresh = ObjectUtils.getNestedAttributePrimitive(reference);
402 if (persistenceStructureService.hasReference(nestedObject.getClass(), propertyToRefresh)
403 || persistenceStructureService.hasCollection(nestedObject.getClass(),
404 propertyToRefresh)) {
405 if (LOG.isDebugEnabled()) {
406 LOG.debug("Refeshing " + ObjectUtils.getNestedAttributePrefix(reference) + " "
407 + ObjectUtils.getNestedAttributePrimitive(reference));
408 }
409 ((PersistableBusinessObject) nestedObject).refreshReferenceObject(propertyToRefresh);
410 }
411 else {
412 // a DD mapping, try to go straight to the
413 // object and refresh it there
414 Object possibleBO = ObjectUtils.getPropertyValue(nestedObject, propertyToRefresh);
415 if (possibleBO != null && possibleBO instanceof PersistableBusinessObject) {
416 if (getDataDictionaryService().hasRelationship(possibleBO.getClass().getName(),
417 propertyToRefresh)) {
418 ((PersistableBusinessObject) possibleBO).refresh();
419 }
420 }
421 }
422 }
423 else {
424 LOG.warn("Expected that a referenceToRefresh ("
425 + reference
426 + ") would be a PersistableBusinessObject or Collection, but instead, it was of class "
427 + nestedObject.getClass().getName());
428 }
429 }
430 }
431 else {
432 if (LOG.isDebugEnabled()) {
433 LOG.debug("Refreshing " + reference);
434 }
435 if (persistenceStructureService.hasReference(getDataObjectClass(), reference)
436 || persistenceStructureService.hasCollection(getDataObjectClass(), reference)) {
437 getBusinessObject().refreshReferenceObject(reference);
438 }
439 else {
440 if (getDataDictionaryService().hasRelationship(getBusinessObject().getClass().getName(),
441 reference)) {
442 // a DD mapping, try to go straight to the
443 // object and refresh it there
444 Object possibleRelationship = ObjectUtils.getPropertyValue(getBusinessObject(),
445 reference);
446 if (possibleRelationship != null) {
447 if (possibleRelationship instanceof PersistableBusinessObject) {
448 ((PersistableBusinessObject) possibleRelationship).refresh();
449 }
450 else if (possibleRelationship instanceof Collection) {
451 // do nothing, probably because it's not
452 // really a collection reference but a
453 // relationship defined in the DD for a
454 // collections lookup
455 // this part will need to be rewritten
456 // when the DD supports true collection
457 // references
458 }
459 else {
460 LOG.warn("Expected that a referenceToRefresh ("
461 + reference
462 + ") would be a PersistableBusinessObject or Collection, but instead, it was of class "
463 + possibleRelationship.getClass().getName());
464 }
465 }
466 }
467 }
468 }
469 }
470 }
471 }
472 }
473
474 public void addMultipleValueLookupResults(MaintenanceDocument document, String collectionName,
475 Collection<PersistableBusinessObject> rawValues, boolean needsBlank, PersistableBusinessObject bo) {
476 Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(bo, collectionName);
477 String docTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
478
479 List<String> duplicateIdentifierFieldsFromDataDictionary = getDuplicateIdentifierFieldsFromDataDictionary(
480 docTypeName, collectionName);
481
482 List<String> existingIdentifierList = getMultiValueIdentifierList(maintCollection,
483 duplicateIdentifierFieldsFromDataDictionary);
484
485 Class collectionClass = getMaintenanceDocumentDictionaryService().getCollectionBusinessObjectClass(docTypeName,
486 collectionName);
487
488 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService()
489 .getMaintainableSections(docTypeName);
490 Map<String, String> template = MaintenanceUtils.generateMultipleValueLookupBOTemplate(sections, collectionName);
491 try {
492 for (PersistableBusinessObject nextBo : rawValues) {
493 PersistableBusinessObject templatedBo;
494 if (needsBlank) {
495 templatedBo = (PersistableBusinessObject) collectionClass.newInstance();
496 }
497 else {
498 // templatedBo = (PersistableBusinessObject)
499 // ObjectUtils.createHybridBusinessObject(collectionClass,
500 // nextBo, template);
501 try {
502 ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService()
503 .getResponsibleModuleService(collectionClass);
504 if (moduleService != null && moduleService.isExternalizable(collectionClass))
505 templatedBo = (PersistableBusinessObject) moduleService
506 .createNewObjectFromExternalizableClass(collectionClass);
507 else
508 templatedBo = (PersistableBusinessObject) collectionClass.newInstance();
509 }
510 catch (Exception e) {
511 throw new RuntimeException("Cannot instantiate " + collectionClass.getName(), e);
512 }
513 // first set the default values specified in the DD
514 setNewCollectionLineDefaultValues(collectionName, templatedBo);
515 // then set the values from the multiple value lookup result
516 ObjectUtils.createHybridBusinessObject(templatedBo, nextBo, template);
517
518 prepareBusinessObjectForAdditionFromMultipleValueLookup(collectionName, templatedBo);
519 }
520 templatedBo.setNewCollectionRecord(true);
521
522 if (!hasBusinessObjectExisted(templatedBo, existingIdentifierList,
523 duplicateIdentifierFieldsFromDataDictionary)) {
524 maintCollection.add(templatedBo);
525
526 }
527 }
528 }
529 catch (Exception e) {
530 LOG.error("Unable to add multiple value lookup results " + e.getMessage());
531 throw new RuntimeException("Unable to add multiple value lookup results " + e.getMessage());
532 }
533 }
534
535 /**
536 * This method is to retrieve a List of fields which are specified in the
537 * maintenance document data dictionary as the
538 * duplicateIdentificationFields. This List is used to determine whether the
539 * new entry being added to the collection is a duplicate entry and if so,
540 * we should not add the new entry to the existing collection
541 *
542 * @param docTypeName
543 * @param collectionName
544 */
545 public List<String> getDuplicateIdentifierFieldsFromDataDictionary(String docTypeName, String collectionName) {
546 List<String> duplicateIdentifierFieldNames = new ArrayList<String>();
547 MaintainableCollectionDefinition collDef = getMaintenanceDocumentDictionaryService().getMaintainableCollection(
548 docTypeName, collectionName);
549 Collection<MaintainableFieldDefinition> fieldDef = collDef.getDuplicateIdentificationFields();
550 for (MaintainableFieldDefinition eachFieldDef : fieldDef) {
551 duplicateIdentifierFieldNames.add(eachFieldDef.getName());
552 }
553 return duplicateIdentifierFieldNames;
554 }
555
556 public List<String> getMultiValueIdentifierList(Collection maintCollection, List<String> duplicateIdentifierFields) {
557 List<String> identifierList = new ArrayList<String>();
558 for (PersistableBusinessObject bo : (Collection<PersistableBusinessObject>) maintCollection) {
559 String uniqueIdentifier = new String();
560 for (String identifierField : duplicateIdentifierFields) {
561 uniqueIdentifier = uniqueIdentifier + identifierField + "-"
562 + ObjectUtils.getPropertyValue(bo, identifierField);
563 }
564 if (StringUtils.isNotEmpty(uniqueIdentifier)) {
565 identifierList.add(uniqueIdentifier);
566 }
567 }
568 return identifierList;
569 }
570
571 public boolean hasBusinessObjectExisted(BusinessObject bo, List<String> existingIdentifierList,
572 List<String> duplicateIdentifierFields) {
573 String uniqueIdentifier = new String();
574 for (String identifierField : duplicateIdentifierFields) {
575 uniqueIdentifier = uniqueIdentifier + identifierField + "-"
576 + ObjectUtils.getPropertyValue(bo, identifierField);
577 }
578 if (existingIdentifierList.contains(uniqueIdentifier)) {
579 return true;
580 }
581 else {
582 return false;
583 }
584 }
585
586 public void prepareBusinessObjectForAdditionFromMultipleValueLookup(String collectionName, BusinessObject bo) {
587 // default implementation does nothing
588 }
589
590 /**
591 * Set the new collection records back to true so they can be deleted (copy
592 * should act like new)
593 *
594 * @see KualiMaintainableImpl#processAfterCopy()
595 */
596 public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> parameters) {
597 try {
598 ObjectUtils.setObjectPropertyDeep(businessObject, KRADPropertyConstants.NEW_COLLECTION_RECORD,
599 boolean.class, true, 2);
600 } catch (Exception e) {
601 LOG.error("unable to set newCollectionRecord property: " + e.getMessage(), e);
602 throw new RuntimeException("unable to set newCollectionRecord property: " + e.getMessage(), e);
603 }
604 }
605
606 @Override
607 public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
608
609 }
610
611 @Override
612 public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) {
613
614 }
615
616 @Override
617 public void processAfterPost(MaintenanceDocument document, Map<String, String[]> requestParameters) {
618
619 }
620
621 @Override
622 public void setDataObject(Object object) {
623 super.setDataObject(object);
624
625 if(object instanceof PersistableBusinessObject) {
626 this.businessObject = (PersistableBusinessObject)object;
627 }
628 }
629
630 @Override
631 public String getDocumentTitle(MaintenanceDocument document) {
632 return super.getDocumentTitle((org.kuali.rice.krad.maintenance.MaintenanceDocument) document);
633 }
634
635 /**
636 * @return Returns the instance of the business object being maintained.
637 */
638 public PersistableBusinessObject getBusinessObject() {
639 return businessObject;
640 }
641
642 /**
643 * @param businessObject
644 * Sets the instance of a business object that will be
645 * maintained.
646 */
647 public void setBusinessObject(PersistableBusinessObject businessObject) {
648 this.businessObject = businessObject;
649 setDataObject(businessObject);
650 }
651
652 /**
653 * @return Returns the boClass.
654 */
655 public Class getBoClass() {
656 return super.getDataObjectClass();
657 }
658
659 /**
660 * @param boClass
661 * The boClass to set.
662 */
663 public void setBoClass(Class boClass) {
664 setDataObjectClass(boClass);
665 }
666
667 /**
668 *
669 * @see Maintainable#setGenerateDefaultValues()
670 */
671 public void setGenerateDefaultValues(String docTypeName) {
672 List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService()
673 .getMaintainableSections(docTypeName);
674 Map defaultValues = new HashMap();
675
676 try {
677 // iterate through section definitions
678 for (Iterator iter = sectionDefinitions.iterator(); iter.hasNext();) {
679
680 MaintainableSectionDefinition maintSectionDef = (MaintainableSectionDefinition) iter.next();
681 Collection maintItems = maintSectionDef.getMaintainableItems();
682 for (Iterator iterator = maintItems.iterator(); iterator.hasNext();) {
683 MaintainableItemDefinition item = (MaintainableItemDefinition) iterator.next();
684
685 if (item instanceof MaintainableFieldDefinition) {
686 MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) item;
687
688 String defaultValue = maintainableFieldDefinition.getDefaultValue();
689 if (defaultValue != null) {
690 if (defaultValue.equals("true")) {
691 defaultValue = "Yes";
692 }
693 else if (defaultValue.equals("false")) {
694 defaultValue = "No";
695 }
696 }
697
698 Class defaultValueFinderClass = maintainableFieldDefinition.getDefaultValueFinderClass();
699 if (defaultValueFinderClass != null) {
700 defaultValue = ((ValueFinder) defaultValueFinderClass.newInstance()).getValue();
701
702 }
703 if (defaultValue != null) {
704 defaultValues.put(item.getName(), defaultValue);
705 }
706 }
707 }
708 }
709 Map cachedValues = FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), defaultValues);
710 }
711 catch (Exception e) {
712 LOG.error("Unable to set default value " + e.getMessage(), e);
713 throw new RuntimeException("Unable to set default value" + e.getMessage(), e);
714 }
715
716 }
717
718 /**
719 *
720 * @see Maintainable#setGenerateBlankRequiredValues()
721 */
722 public void setGenerateBlankRequiredValues(String docTypeName) {
723 try {
724 List<MaintainableSectionDefinition> sectionDefinitions = getMaintenanceDocumentDictionaryService()
725 .getMaintainableSections(docTypeName);
726 Map<String, String> defaultValues = new HashMap<String, String>();
727
728 for (MaintainableSectionDefinition maintSectionDef : sectionDefinitions) {
729 for (MaintainableItemDefinition item : maintSectionDef.getMaintainableItems()) {
730 if (item instanceof MaintainableFieldDefinition) {
731 MaintainableFieldDefinition maintainableFieldDefinition = (MaintainableFieldDefinition) item;
732 if (maintainableFieldDefinition.isRequired()
733 && maintainableFieldDefinition.isUnconditionallyReadOnly()) {
734 Object currPropVal = ObjectUtils.getPropertyValue(this.getBusinessObject(), item.getName());
735 if (currPropVal == null
736 || (currPropVal instanceof String && StringUtils.isBlank((String) currPropVal))) {
737 Class<? extends ValueFinder> defaultValueFinderClass = maintainableFieldDefinition
738 .getDefaultValueFinderClass();
739 if (defaultValueFinderClass != null) {
740 String defaultValue = defaultValueFinderClass.newInstance().getValue();
741 if (defaultValue != null) {
742 defaultValues.put(item.getName(), defaultValue);
743 }
744 }
745 }
746 }
747 }
748 }
749 }
750 FieldUtils.populateBusinessObjectFromMap(getBusinessObject(), defaultValues);
751 }
752 catch (Exception e) {
753 LOG.error("Unable to set blank required value " + e.getMessage(), e);
754 throw new RuntimeException("Unable to set blank required value" + e.getMessage(), e);
755 }
756 }
757
758 @Deprecated
759 public void processAfterAddLine(String colName, Class colClass) {
760 }
761
762 /**
763 * @see Maintainable#processBeforeAddLine(java.lang.String,
764 * java.lang.Class, org.kuali.rice.krad.bo.BusinessObject)
765 */
766 public void processBeforeAddLine(String colName, Class colClass, BusinessObject addBO) {
767 }
768
769 /**
770 * @see Maintainable#getShowInactiveRecords(java.lang.String)
771 */
772 public boolean getShowInactiveRecords(String collectionName) {
773 return InactiveRecordsHidingUtils.getShowInactiveRecords(inactiveRecordDisplay, collectionName);
774 }
775
776 /**
777 * @see Maintainable#setShowInactiveRecords(java.lang.String,
778 * boolean)
779 */
780 public void setShowInactiveRecords(String collectionName, boolean showInactive) {
781 InactiveRecordsHidingUtils.setShowInactiveRecords(inactiveRecordDisplay, collectionName, showInactive);
782 }
783
784 /**
785 * @return the inactiveRecordDisplay
786 */
787 public Map<String, Boolean> getInactiveRecordDisplay() {
788 return inactiveRecordDisplay;
789 }
790
791 public void addNewLineToCollection(String collectionName) {
792
793 if (LOG.isDebugEnabled()) {
794 LOG.debug("addNewLineToCollection( " + collectionName + " )");
795 }
796 // get the new line from the map
797 PersistableBusinessObject addLine = newCollectionLines.get(collectionName);
798 if (addLine != null) {
799 // mark the isNewCollectionRecord so the option to delete this line
800 // will be presented
801 addLine.setNewCollectionRecord(true);
802
803 // if we add back add button on sub collection of an "add line" we
804 // may need extra logic here
805
806 // get the collection from the business object
807 Collection maintCollection = (Collection) ObjectUtils.getPropertyValue(getBusinessObject(), collectionName);
808 // add the line to the collection
809 maintCollection.add(addLine);
810 // refresh parent object since attributes could of changed prior to
811 // user clicking add
812
813 String referencesToRefresh = LookupUtils
814 .convertReferencesToSelectCollectionToString(getAllRefreshableReferences(getBusinessObject()
815 .getClass()));
816 if (LOG.isInfoEnabled()) {
817 LOG.info("References to refresh for adding line to collection " + collectionName + ": "
818 + referencesToRefresh);
819 }
820 refreshReferences(referencesToRefresh);
821 }
822
823 initNewCollectionLine(collectionName);
824
825 }
826
827 public PersistableBusinessObject getNewCollectionLine(String collectionName) {
828 if (LOG.isDebugEnabled()) {
829 // LOG.debug( this + ") getNewCollectionLine( " + collectionName +
830 // ")", new Exception( "tracing exception") );
831 LOG.debug("newCollectionLines: " + newCollectionLines);
832 }
833 PersistableBusinessObject addLine = newCollectionLines.get(collectionName);
834 if (addLine == null) {
835 addLine = initNewCollectionLine(collectionName);
836 }
837 return addLine;
838 }
839
840 public PersistableBusinessObject initNewCollectionLine(String collectionName) {
841 if (LOG.isDebugEnabled()) {
842 LOG.debug("initNewCollectionLine( " + collectionName + " )");
843 }
844 // try to get the object from the map
845 // BusinessObject addLine = newCollectionLines.get( collectionName );
846 // if ( addLine == null ) {
847 // if not there, instantiate a new one
848 PersistableBusinessObject addLine;
849 try {
850 addLine = (PersistableBusinessObject) getMaintenanceDocumentDictionaryService()
851 .getCollectionBusinessObjectClass(getDocumentTypeName(), collectionName).newInstance();
852 }
853 catch (Exception ex) {
854 LOG.error("unable to instantiate new collection line", ex);
855 throw new RuntimeException("unable to instantiate new collection line", ex);
856 }
857 // and add it to the map
858 newCollectionLines.put(collectionName, addLine);
859 // }
860 // set its values to the defaults
861 setNewCollectionLineDefaultValues(collectionName, addLine);
862 return addLine;
863 }
864
865 /**
866 *
867 * @see Maintainable#populateNewCollectionLines(java.util.Map)
868 */
869 public Map<String, String> populateNewCollectionLines(Map<String, String> fieldValues,
870 MaintenanceDocument maintenanceDocument, String methodToCall) {
871 if (LOG.isDebugEnabled()) {
872 LOG.debug("populateNewCollectionLines: " + fieldValues);
873 }
874 fieldValues = decryptEncryptedData(fieldValues, maintenanceDocument, methodToCall);
875
876 Map<String, String> cachedValues = new HashMap<String, String>();
877
878 // loop over all collections with an enabled add line
879 List<MaintainableCollectionDefinition> collections = getMaintenanceDocumentDictionaryService()
880 .getMaintainableCollections(getDocumentTypeName());
881
882 for (MaintainableCollectionDefinition coll : collections) {
883 // get the collection name
884 String collName = coll.getName();
885 if (LOG.isDebugEnabled()) {
886 LOG.debug("checking for collection: " + collName);
887 }
888 // build a map for that collection
889 Map<String, String> collectionValues = new HashMap<String, String>();
890 Map<String, String> subCollectionValues = new HashMap<String, String>();
891 // loop over the collection, extracting entries with a matching
892 // prefix
893 for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
894 String key = entry.getKey();
895 if (key.startsWith(collName)) {
896 String subStrKey = key.substring(collName.length() + 1);
897 // check for subcoll w/ '[', set collName to propername and
898 // put in correct name for collection values (i.e. strip
899 // '*[x].')
900 if (key.contains("[")) {
901
902 // collName = StringUtils.substringBeforeLast(key,"[");
903
904 // need the whole thing if subcollection
905 subCollectionValues.put(key, entry.getValue());
906 }
907 else {
908 collectionValues.put(subStrKey, entry.getValue());
909 }
910 }
911 }
912 // send those values to the business object
913 if (LOG.isDebugEnabled()) {
914 LOG.debug("values for collection: " + collectionValues);
915 }
916 cachedValues.putAll(FieldUtils.populateBusinessObjectFromMap(getNewCollectionLine(collName),
917 collectionValues, KRADConstants.MAINTENANCE_ADD_PREFIX + collName + "."));
918 performFieldForceUpperCase(getNewCollectionLine(collName), collectionValues);
919
920 cachedValues.putAll(populateNewSubCollectionLines(coll, subCollectionValues));
921 }
922
923 // cachedValues.putAll( FieldUtils.populateBusinessObjectFromMap( ))
924 return cachedValues;
925 }
926
927 /*
928 * Yes, I think this could be merged with the above code - I'm leaving it
929 * separate until I figure out of there are any issues which would reqire
930 * that it be separated.
931 */
932 protected Map populateNewSubCollectionLines(MaintainableCollectionDefinition parentCollection, Map fieldValues) {
933 if (LOG.isDebugEnabled()) {
934 LOG.debug("populateNewSubCollectionLines: " + fieldValues);
935 }
936 Map cachedValues = new HashMap();
937
938 for (MaintainableCollectionDefinition coll : parentCollection.getMaintainableCollections()) {
939 // get the collection name
940 String collName = coll.getName();
941
942 if (LOG.isDebugEnabled()) {
943 LOG.debug("checking for sub collection: " + collName);
944 }
945 Map<String, String> parents = new HashMap<String, String>();
946 // get parents from list
947 for (Object entry : fieldValues.entrySet()) {
948 String key = (String) ((Map.Entry) entry).getKey();
949 if (key.contains(collName)) {
950 parents.put(StringUtils.substringBefore(key, "."), "");
951 }
952 }
953
954 for (String parent : parents.keySet()) {
955 // build a map for that collection
956 Map<String, Object> collectionValues = new HashMap<String, Object>();
957 // loop over the collection, extracting entries with a matching
958 // prefix
959 for (Object entry : fieldValues.entrySet()) {
960 String key = (String) ((Map.Entry) entry).getKey();
961 if (key.contains(parent)) {
962 String substr = StringUtils.substringAfterLast(key, ".");
963 collectionValues.put(substr, ((Map.Entry) entry).getValue());
964 }
965 }
966 // send those values to the business object
967 if (LOG.isDebugEnabled()) {
968 LOG.debug("values for sub collection: " + collectionValues);
969 }
970 GlobalVariables.getMessageMap().addToErrorPath(
971 KRADConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName);
972 cachedValues.putAll(FieldUtils.populateBusinessObjectFromMap(getNewCollectionLine(parent + "."
973 + collName), collectionValues, KRADConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName
974 + "."));
975 performFieldForceUpperCase(getNewCollectionLine(parent + "." + collName), collectionValues);
976 GlobalVariables.getMessageMap().removeFromErrorPath(
977 KRADConstants.MAINTENANCE_ADD_PREFIX + parent + "." + collName);
978 }
979
980 cachedValues.putAll(populateNewSubCollectionLines(coll, fieldValues));
981 }
982
983 return cachedValues;
984 }
985
986 public Collection<String> getAffectedReferencesFromLookup(BusinessObject baseBO, String attributeName,
987 String collectionPrefix) {
988 PersistenceStructureService pss = getPersistenceStructureService();
989 String nestedBOPrefix = "";
990 if (ObjectUtils.isNestedAttribute(attributeName)) {
991 // if we're performing a lookup on a nested attribute, we need to
992 // use the nested BO all the way down the chain
993 nestedBOPrefix = ObjectUtils.getNestedAttributePrefix(attributeName);
994
995 // renormalize the base BO so that the attribute name is not nested
996 // anymore
997 Class reference = ObjectUtils.getPropertyType(baseBO, nestedBOPrefix, pss);
998 if (!(PersistableBusinessObject.class.isAssignableFrom(reference))) {
999 return new ArrayList<String>();
1000 }
1001
1002 try {
1003 baseBO = (PersistableBusinessObject) reference.newInstance();
1004 }
1005 catch (InstantiationException e) {
1006 LOG.error(e);
1007 }
1008 catch (IllegalAccessException e) {
1009 LOG.error(e);
1010 }
1011 attributeName = ObjectUtils.getNestedAttributePrimitive(attributeName);
1012 }
1013
1014 if (baseBO == null) {
1015 return new ArrayList<String>();
1016 }
1017
1018 Map<String, Class> referenceNameToClassFromPSS = LookupUtils.getPrimitiveReference(baseBO, attributeName);
1019 if (referenceNameToClassFromPSS.size() > 1) {
1020 LOG.error("LookupUtils.getPrimitiveReference return results should only have at most one element");
1021 }
1022
1023 BusinessObjectMetaDataService businessObjectMetaDataService = getBusinessObjectMetaDataService();
1024 DataObjectRelationship relationship = businessObjectMetaDataService.getBusinessObjectRelationship(baseBO,
1025 attributeName);
1026 if (relationship == null) {
1027 return new ArrayList<String>();
1028 }
1029
1030 Map<String, String> fkToPkMappings = relationship.getParentToChildReferences();
1031
1032 Collection<String> affectedReferences = generateAllAffectedReferences(baseBO.getClass(), fkToPkMappings,
1033 nestedBOPrefix, collectionPrefix);
1034 if (LOG.isDebugEnabled()) {
1035 LOG.debug("References affected by a lookup on BO attribute \"" + collectionPrefix + nestedBOPrefix + "."
1036 + attributeName + ": " + affectedReferences);
1037 }
1038
1039 return affectedReferences;
1040 }
1041
1042 protected boolean isRelationshipRefreshable(Class boClass, String relationshipName) {
1043 if (getPersistenceStructureService().isPersistable(boClass)) {
1044 if (getPersistenceStructureService().hasCollection(boClass, relationshipName)) {
1045 return !getPersistenceStructureService().isCollectionUpdatable(boClass, relationshipName);
1046 }
1047 else if (getPersistenceStructureService().hasReference(boClass, relationshipName)) {
1048 return !getPersistenceStructureService().isReferenceUpdatable(boClass, relationshipName);
1049 }
1050 // else, assume that the relationship is defined in the DD
1051 }
1052
1053 return true;
1054 }
1055
1056 protected Collection<String> generateAllAffectedReferences(Class boClass, Map<String, String> fkToPkMappings,
1057 String nestedBOPrefix, String collectionPrefix) {
1058 Set<String> allAffectedReferences = new HashSet<String>();
1059 DataDictionaryService dataDictionaryService = getDataDictionaryService();
1060 PersistenceStructureService pss = getPersistenceStructureService();
1061
1062 collectionPrefix = StringUtils.isBlank(collectionPrefix) ? "" : collectionPrefix;
1063
1064 // retrieve the attributes that are affected by a lookup on
1065 // attributeName.
1066 Collection<String> attributeReferenceFKAttributes = fkToPkMappings.keySet();
1067
1068 // a lookup on an attribute may cause other attributes to be updated
1069 // (e.g. account code lookup would also affect chart code)
1070 // build a list of all affected FK values via mapKeyFields above, and
1071 // for each FK, see if there are any non-updatable references with that
1072 // FK
1073
1074 // deal with regular simple references (<reference-descriptor>s in OJB)
1075 for (String fkAttribute : attributeReferenceFKAttributes) {
1076 for (String affectedReference : pss.getReferencesForForeignKey(boClass, fkAttribute).keySet()) {
1077 if (isRelationshipRefreshable(boClass, affectedReference)) {
1078 if (StringUtils.isBlank(nestedBOPrefix)) {
1079 allAffectedReferences.add(collectionPrefix + affectedReference);
1080 }
1081 else {
1082 allAffectedReferences.add(collectionPrefix + nestedBOPrefix + "." + affectedReference);
1083 }
1084 }
1085 }
1086 }
1087
1088 // now with collection references (<collection-descriptor>s in OJB)
1089 for (String collectionName : pss.listCollectionObjectTypes(boClass).keySet()) {
1090 if (isRelationshipRefreshable(boClass, collectionName)) {
1091 Map<String, String> keyMappingsForCollection = pss.getInverseForeignKeysForCollection(boClass,
1092 collectionName);
1093 for (String collectionForeignKey : keyMappingsForCollection.keySet()) {
1094 if (attributeReferenceFKAttributes.contains(collectionForeignKey)) {
1095 if (StringUtils.isBlank(nestedBOPrefix)) {
1096 allAffectedReferences.add(collectionPrefix + collectionName);
1097 }
1098 else {
1099 allAffectedReferences.add(collectionPrefix + nestedBOPrefix + "." + collectionName);
1100 }
1101 }
1102 }
1103 }
1104 }
1105
1106 // now use the DD to compute more affected references
1107 List<String> ddDefinedRelationships = dataDictionaryService.getRelationshipNames(boClass.getName());
1108 for (String ddRelationship : ddDefinedRelationships) {
1109 // note that this map is PK (key/target) => FK (value/source)
1110 Map<String, String> referencePKtoFKmappings = dataDictionaryService.getRelationshipAttributeMap(
1111 boClass.getName(), ddRelationship);
1112 for (String sourceAttribute : referencePKtoFKmappings.values()) {
1113 // the sourceAttribute is the FK pointing to the target
1114 // attribute (PK)
1115 if (attributeReferenceFKAttributes.contains(sourceAttribute)) {
1116 for (String affectedReference : dataDictionaryService.getRelationshipEntriesForSourceAttribute(
1117 boClass.getName(), sourceAttribute)) {
1118 if (isRelationshipRefreshable(boClass, ddRelationship)) {
1119 if (StringUtils.isBlank(nestedBOPrefix)) {
1120 allAffectedReferences.add(affectedReference);
1121 }
1122 else {
1123 allAffectedReferences.add(nestedBOPrefix + "." + affectedReference);
1124 }
1125 }
1126 }
1127 }
1128 }
1129 }
1130 return allAffectedReferences;
1131 }
1132
1133 protected Collection<String> getAllRefreshableReferences(Class boClass) {
1134 HashSet<String> references = new HashSet<String>();
1135 for (String referenceName : getPersistenceStructureService().listReferenceObjectFields(boClass).keySet()) {
1136 if (isRelationshipRefreshable(boClass, referenceName)) {
1137 references.add(referenceName);
1138 }
1139 }
1140 for (String collectionName : getPersistenceStructureService().listCollectionObjectTypes(boClass).keySet()) {
1141 if (isRelationshipRefreshable(boClass, collectionName)) {
1142 references.add(collectionName);
1143 }
1144 }
1145 for (String relationshipName : getDataDictionaryService().getRelationshipNames(boClass.getName())) {
1146 if (isRelationshipRefreshable(boClass, relationshipName)) {
1147 references.add(relationshipName);
1148 }
1149 }
1150 return references;
1151 }
1152
1153 protected void setNewCollectionLineDefaultValues(String collectionName, PersistableBusinessObject addLine) {
1154 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(addLine);
1155 for (int i = 0; i < descriptors.length; ++i) {
1156 PropertyDescriptor propertyDescriptor = descriptors[i];
1157
1158 String fieldName = propertyDescriptor.getName();
1159 Class propertyType = propertyDescriptor.getPropertyType();
1160 String value = getMaintenanceDocumentDictionaryService().getCollectionFieldDefaultValue(getDocumentTypeName(),
1161 collectionName, fieldName);
1162
1163 if (value != null) {
1164 try {
1165 ObjectUtils.setObjectProperty(addLine, fieldName, propertyType, value);
1166 }
1167 catch (Exception ex) {
1168 LOG.error("Unable to set default property of collection object: " + "\nobject: " + addLine
1169 + "\nfieldName=" + fieldName + "\npropertyType=" + propertyType + "\nvalue=" + value, ex);
1170 }
1171 }
1172
1173 }
1174 }
1175
1176 /**
1177 * @see Maintainable#clearBusinessObjectOfRestrictedValues(org.kuali.rice.kns.document.authorization.MaintenanceDocumentRestrictions)
1178 */
1179 public void clearBusinessObjectOfRestrictedValues(MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
1180 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService()
1181 .getMaintainableSections(getDocumentTypeName());
1182 for (MaintainableSectionDefinition sectionDefinition : sections) {
1183 for (MaintainableItemDefinition itemDefinition : sectionDefinition.getMaintainableItems()) {
1184 if (itemDefinition instanceof MaintainableFieldDefinition) {
1185 clearFieldRestrictedValues("", businessObject, (MaintainableFieldDefinition) itemDefinition,
1186 maintenanceDocumentRestrictions);
1187 }
1188 else if (itemDefinition instanceof MaintainableCollectionDefinition) {
1189 clearCollectionRestrictedValues("", businessObject,
1190 (MaintainableCollectionDefinition) itemDefinition, maintenanceDocumentRestrictions);
1191 }
1192 }
1193 }
1194 }
1195
1196 protected void clearCollectionRestrictedValues(String fieldNamePrefix, BusinessObject businessObject,
1197 MaintainableCollectionDefinition collectionDefinition,
1198 MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
1199 String collectionName = fieldNamePrefix + collectionDefinition.getName();
1200 Collection<BusinessObject> collection = (Collection<BusinessObject>) ObjectUtils.getPropertyValue(
1201 businessObject, collectionDefinition.getName());
1202
1203 if (collection != null) {
1204 int i = 0;
1205 // even though it's technically a Collection, we're going to index
1206 // it like a list
1207 for (BusinessObject collectionItem : collection) {
1208 String collectionItemNamePrefix = collectionName + "[" + i + "].";
1209 for (MaintainableCollectionDefinition subCollectionDefinition : collectionDefinition
1210 .getMaintainableCollections()) {
1211 clearCollectionRestrictedValues(collectionItemNamePrefix, collectionItem, subCollectionDefinition,
1212 maintenanceDocumentRestrictions);
1213 }
1214 for (MaintainableFieldDefinition fieldDefinition : collectionDefinition.getMaintainableFields()) {
1215 clearFieldRestrictedValues(collectionItemNamePrefix, collectionItem, fieldDefinition,
1216 maintenanceDocumentRestrictions);
1217 }
1218 i++;
1219 }
1220 }
1221 }
1222
1223 protected void clearFieldRestrictedValues(String fieldNamePrefix, BusinessObject businessObject,
1224 MaintainableFieldDefinition fieldDefinition, MaintenanceDocumentRestrictions maintenanceDocumentRestrictions) {
1225 String fieldName = fieldNamePrefix + fieldDefinition.getName();
1226
1227 FieldRestriction fieldRestriction = maintenanceDocumentRestrictions.getFieldRestriction(fieldName);
1228 if (fieldRestriction.isRestricted()) {
1229 String defaultValue = null;
1230 if (StringUtils.isNotBlank(fieldDefinition.getDefaultValue())) {
1231 defaultValue = fieldDefinition.getDefaultValue();
1232 }
1233 else if (fieldDefinition.getDefaultValueFinderClass() != null) {
1234 try {
1235 defaultValue = ((ValueFinder) fieldDefinition.getDefaultValueFinderClass().newInstance())
1236 .getValue();
1237 }
1238 catch (Exception e) {
1239 defaultValue = null;
1240 LOG.error("Error trying to instantiate ValueFinder or to determine ValueFinder for doc type: "
1241 + getDocumentTypeName() + " field name " + fieldDefinition.getName() + " with field prefix: "
1242 + fieldNamePrefix, e);
1243 }
1244 }
1245 try {
1246 ObjectUtils.setObjectProperty(businessObject, fieldDefinition.getName(), defaultValue);
1247 }
1248 catch (Exception e) {
1249 // throw an exception, because we don't want users to be able to
1250 // see the restricted value
1251 LOG.error("Unable to clear maintenance document values for field name: " + fieldName
1252 + " default value: " + defaultValue, e);
1253 throw new RuntimeException("Unable to clear maintenance document values for field name: " + fieldName,
1254 e);
1255 }
1256 }
1257 }
1258
1259 protected void performForceUpperCase(Map fieldValues) {
1260 List<MaintainableSectionDefinition> sections = getMaintenanceDocumentDictionaryService()
1261 .getMaintainableSections(getDocumentTypeName());
1262 for (MaintainableSectionDefinition sectionDefinition : sections) {
1263 for (MaintainableItemDefinition itemDefinition : sectionDefinition.getMaintainableItems()) {
1264 if (itemDefinition instanceof MaintainableFieldDefinition) {
1265 performFieldForceUpperCase("", businessObject, (MaintainableFieldDefinition) itemDefinition,
1266 fieldValues);
1267 }
1268 else if (itemDefinition instanceof MaintainableCollectionDefinition) {
1269 performCollectionForceUpperCase("", businessObject,
1270 (MaintainableCollectionDefinition) itemDefinition, fieldValues);
1271
1272 }
1273 }
1274 }
1275 }
1276
1277 protected void performFieldForceUpperCase(String fieldNamePrefix, BusinessObject bo,
1278 MaintainableFieldDefinition fieldDefinition, Map fieldValues) {
1279 MessageMap errorMap = GlobalVariables.getMessageMap();
1280 String fieldName = fieldDefinition.getName();
1281 String mapKey = fieldNamePrefix + fieldName;
1282 if (fieldValues != null && fieldValues.get(mapKey) != null) {
1283 if (PropertyUtils.isWriteable(bo, fieldName) && ObjectUtils.getNestedValue(bo, fieldName) != null) {
1284
1285 try {
1286 Class type = ObjectUtils.easyGetPropertyType(bo, fieldName);
1287 // convert to upperCase based on data dictionary
1288 Class businessObjectClass = bo.getClass();
1289 boolean upperCase = false;
1290 try {
1291 upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass,
1292 fieldName);
1293 }
1294 catch (UnknownBusinessClassAttributeException t) {
1295 boolean catchme = true;
1296 // throw t;
1297 }
1298
1299 Object fieldValue = ObjectUtils.getNestedValue(bo, fieldName);
1300
1301 if (upperCase && fieldValue instanceof String) {
1302 fieldValue = ((String) fieldValue).toUpperCase();
1303 }
1304 ObjectUtils.setObjectProperty(bo, fieldName, type, fieldValue);
1305 }
1306 catch (FormatException e) {
1307 errorMap.putError(fieldName, e.getErrorKey(), e.getErrorArgs());
1308 }
1309 catch (IllegalAccessException e) {
1310 LOG.error("unable to populate business object" + e.getMessage());
1311 throw new RuntimeException(e.getMessage(), e);
1312 }
1313 catch (InvocationTargetException e) {
1314 LOG.error("unable to populate business object" + e.getMessage());
1315 throw new RuntimeException(e.getMessage(), e);
1316 }
1317 catch (NoSuchMethodException e) {
1318 LOG.error("unable to populate business object" + e.getMessage());
1319 throw new RuntimeException(e.getMessage(), e);
1320 }
1321 }
1322 }
1323 }
1324
1325 protected void performCollectionForceUpperCase(String fieldNamePrefix, BusinessObject bo,
1326 MaintainableCollectionDefinition collectionDefinition, Map fieldValues) {
1327 String collectionName = fieldNamePrefix + collectionDefinition.getName();
1328 Collection<BusinessObject> collection = (Collection<BusinessObject>) ObjectUtils.getPropertyValue(bo,
1329 collectionDefinition.getName());
1330 if (collection != null) {
1331 int i = 0;
1332 // even though it's technically a Collection, we're going to index
1333 // it like a list
1334 for (BusinessObject collectionItem : collection) {
1335 String collectionItemNamePrefix = collectionName + "[" + i + "].";
1336 // String collectionItemNamePrefix = "";
1337 for (MaintainableFieldDefinition fieldDefinition : collectionDefinition.getMaintainableFields()) {
1338 performFieldForceUpperCase(collectionItemNamePrefix, collectionItem, fieldDefinition, fieldValues);
1339 }
1340 for (MaintainableCollectionDefinition subCollectionDefinition : collectionDefinition
1341 .getMaintainableCollections()) {
1342 performCollectionForceUpperCase(collectionItemNamePrefix, collectionItem, subCollectionDefinition,
1343 fieldValues);
1344 }
1345 i++;
1346 }
1347 }
1348 }
1349
1350 protected void performFieldForceUpperCase(BusinessObject bo, Map fieldValues) {
1351 MessageMap errorMap = GlobalVariables.getMessageMap();
1352
1353 try {
1354 for (Iterator iter = fieldValues.keySet().iterator(); iter.hasNext();) {
1355 String propertyName = (String) iter.next();
1356
1357 if (PropertyUtils.isWriteable(bo, propertyName) && fieldValues.get(propertyName) != null) {
1358 // if the field propertyName is a valid property on the bo
1359 // class
1360 Class type = ObjectUtils.easyGetPropertyType(bo, propertyName);
1361 try {
1362 // Keep the convert to upperCase logic here. It will be
1363 // used in populateNewCollectionLines,
1364 // populateNewSubCollectionLines
1365 // convert to upperCase based on data dictionary
1366 Class businessObjectClass = bo.getClass();
1367 boolean upperCase = false;
1368 try {
1369 upperCase = getDataDictionaryService().getAttributeForceUppercase(businessObjectClass,
1370 propertyName);
1371 }
1372 catch (UnknownBusinessClassAttributeException t) {
1373 boolean catchme = true;
1374 // throw t;
1375 }
1376
1377 Object fieldValue = fieldValues.get(propertyName);
1378
1379 if (upperCase && fieldValue instanceof String) {
1380 fieldValue = ((String) fieldValue).toUpperCase();
1381 }
1382 ObjectUtils.setObjectProperty(bo, propertyName, type, fieldValue);
1383 }
1384 catch (FormatException e) {
1385 errorMap.putError(propertyName, e.getErrorKey(), e.getErrorArgs());
1386 }
1387 }
1388 }
1389 }
1390 catch (IllegalAccessException e) {
1391 LOG.error("unable to populate business object" + e.getMessage());
1392 throw new RuntimeException(e.getMessage(), e);
1393 }
1394 catch (InvocationTargetException e) {
1395 LOG.error("unable to populate business object" + e.getMessage());
1396 throw new RuntimeException(e.getMessage(), e);
1397 }
1398 catch (NoSuchMethodException e) {
1399 LOG.error("unable to populate business object" + e.getMessage());
1400 throw new RuntimeException(e.getMessage(), e);
1401 }
1402
1403 }
1404
1405 /**
1406 * By default a maintainable is not external
1407 *
1408 * @see Maintainable#isExternalBusinessObject()
1409 */
1410 public boolean isExternalBusinessObject() {
1411 return false;
1412 }
1413
1414 /**
1415 * @see Maintainable#getExternalBusinessObject()
1416 */
1417 public void prepareBusinessObject(BusinessObject businessObject) {
1418 // Do nothing by default
1419 }
1420
1421 // 3070
1422 public void deleteBusinessObject() {
1423 if (businessObject == null)
1424 return;
1425
1426 KRADServiceLocator.getBusinessObjectService().delete(businessObject);
1427 businessObject = null;
1428 }
1429
1430 public boolean isOldBusinessObjectInDocument() {
1431 return super.isOldDataObjectInDocument();
1432 }
1433
1434 protected BusinessObjectDictionaryService getBusinessObjectDictionaryService() {
1435 if (businessObjectDictionaryService == null) {
1436 businessObjectDictionaryService = KNSServiceLocator.getBusinessObjectDictionaryService();
1437 }
1438 return businessObjectDictionaryService;
1439 }
1440
1441 protected PersonService getPersonService() {
1442 if (personService == null) {
1443 personService = KimApiServiceLocator.getPersonService();
1444 }
1445 return personService;
1446 }
1447
1448 protected BusinessObjectMetaDataService getBusinessObjectMetaDataService() {
1449 if (businessObjectMetaDataService == null) {
1450 businessObjectMetaDataService = KNSServiceLocator.getBusinessObjectMetaDataService();
1451 }
1452 return businessObjectMetaDataService;
1453 }
1454
1455 protected BusinessObjectAuthorizationService getBusinessObjectAuthorizationService() {
1456 if (businessObjectAuthorizationService == null) {
1457 businessObjectAuthorizationService = KNSServiceLocator.getBusinessObjectAuthorizationService();
1458 }
1459 return businessObjectAuthorizationService;
1460 }
1461
1462 protected DocumentHelperService getDocumentHelperService() {
1463 if (documentHelperService == null) {
1464 documentHelperService = KNSServiceLocator.getDocumentHelperService();
1465 }
1466 return documentHelperService;
1467 }
1468
1469 public void setBusinessObjectDictionaryService(BusinessObjectDictionaryService businessObjectDictionaryService) {
1470 this.businessObjectDictionaryService = businessObjectDictionaryService;
1471 }
1472
1473 public void setPersonService(PersonService personService) {
1474 this.personService = personService;
1475 }
1476
1477 public void setBusinessObjectMetaDataService(BusinessObjectMetaDataService businessObjectMetaDataService) {
1478 this.businessObjectMetaDataService = businessObjectMetaDataService;
1479 }
1480
1481 public void setBusinessObjectAuthorizationService(
1482 BusinessObjectAuthorizationService businessObjectAuthorizationService) {
1483 this.businessObjectAuthorizationService = businessObjectAuthorizationService;
1484 }
1485
1486 public void setDocumentHelperService(DocumentHelperService documentHelperService) {
1487 this.documentHelperService = documentHelperService;
1488 }
1489
1490 public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
1491 if (maintenanceDocumentDictionaryService == null) {
1492 this.maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService();
1493 }
1494 return maintenanceDocumentDictionaryService;
1495 }
1496
1497 public void setMaintenanceDocumentDictionaryService(
1498 MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService) {
1499 this.maintenanceDocumentDictionaryService = maintenanceDocumentDictionaryService;
1500 }
1501 }