001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.core.service.impl;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.commons.lang.StringUtils;
024: import org.kuali.RiceKeyConstants;
025: import org.kuali.core.bo.PersistableBusinessObject;
026: import org.kuali.core.datadictionary.DataDictionary;
027: import org.kuali.core.datadictionary.MaintainableCollectionDefinition;
028: import org.kuali.core.datadictionary.MaintainableFieldDefinition;
029: import org.kuali.core.datadictionary.MaintainableItemDefinition;
030: import org.kuali.core.datadictionary.MaintainableSectionDefinition;
031: import org.kuali.core.datadictionary.MaintenanceDocumentEntry;
032: import org.kuali.core.document.MaintenanceDocument;
033: import org.kuali.core.lookup.valueFinder.ValueFinder;
034: import org.kuali.core.maintenance.Maintainable;
035: import org.kuali.core.maintenance.rules.MaintenanceDocumentRuleBase;
036: import org.kuali.core.service.DataDictionaryService;
037: import org.kuali.core.service.MaintenanceDocumentDictionaryService;
038: import org.kuali.core.util.GlobalVariables;
039: import org.kuali.core.util.ObjectUtils;
040:
041: /**
042: * This class is the service implementation for the MaintenanceDocumentDictionary structure. Defines the API for the interacting
043: * with Document-related entries in the data dictionary. This is the default implementation, that is delivered with Kuali.
044: */
045: public class MaintenanceDocumentDictionaryServiceImpl implements
046: MaintenanceDocumentDictionaryService {
047: protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
048: .getLogger(MaintenanceDocumentDictionaryServiceImpl.class);
049:
050: private DataDictionaryService dataDictionaryService;
051:
052: /**
053: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getMaintenanceLabel(java.lang.String)
054: */
055: public String getMaintenanceLabel(String docTypeName) {
056: String label = null;
057:
058: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
059: if (entry != null) {
060: label = entry.getLabel();
061: }
062:
063: return label;
064: }
065:
066: /**
067: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getMaintenanceDescription(java.lang.String)
068: */
069: public String getMaintenanceDescription(String docTypeName) {
070: String description = null;
071:
072: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
073: if (entry != null) {
074: description = entry.getDescription();
075: }
076:
077: return description;
078: }
079:
080: /**
081: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getMaintainableClass(java.lang.String)
082: */
083: public Class getMaintainableClass(String docTypeName) {
084: Class maintainableClass = null;
085:
086: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
087: if (entry != null) {
088: LOG
089: .debug("suppling a generic Rule to insure basic validation");
090: maintainableClass = entry.getMaintainableClass();
091: }
092:
093: return maintainableClass;
094: }
095:
096: /**
097: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getBusinessObjectClass(java.lang.String)
098: */
099: public Class getBusinessObjectClass(String docTypeName) {
100: Class businessObjectClass = null;
101:
102: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
103: if (entry != null) {
104: businessObjectClass = entry.getBusinessObjectClass();
105: }
106:
107: return businessObjectClass;
108: }
109:
110: /**
111: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getDocumentTypeName(java.lang.Class)
112: */
113: public String getDocumentTypeName(Class businessObjectClass) {
114: String documentTypeName = null;
115:
116: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(businessObjectClass);
117: if (entry != null) {
118: documentTypeName = entry.getDocumentTypeName();
119: }
120:
121: return documentTypeName;
122: }
123:
124: /**
125: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getMaintainableSections(java.lang.String)
126: */
127: public List getMaintainableSections(String docTypeName) {
128: List sections = null;
129:
130: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
131: if (entry != null) {
132: sections = entry.getMaintainableSections();
133: }
134:
135: return sections;
136: }
137:
138: /**
139: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getBusinessRulesClass(MaintenanceDocument)
140: */
141: public Class getBusinessRulesClass(MaintenanceDocument document) {
142: Maintainable maintainable = document.getOldMaintainableObject();
143: if (maintainable == null) {
144: throw new IllegalArgumentException(
145: "unable to determine documentType for maintenanceDocument with no oldMaintainableObject");
146: }
147:
148: Class businessRulesClass = null;
149:
150: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(maintainable
151: .getBoClass());
152: if (entry != null) {
153: businessRulesClass = entry.getBusinessRulesClass();
154: }
155:
156: if (businessRulesClass == null) {
157: return MaintenanceDocumentRuleBase.class; // default to a generic rule that will enforce Required fields
158: }
159:
160: LOG.info("return class: " + businessRulesClass.getName());
161:
162: return businessRulesClass;
163: }
164:
165: /**
166: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getDefaultExistenceChecks(java.lang.Class)
167: */
168: public Collection getDefaultExistenceChecks(
169: Class businessObjectClass) {
170: return getDefaultExistenceChecks(getDocumentTypeName(businessObjectClass));
171: }
172:
173: /**
174: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getDefaultExistenceChecks(java.lang.String)
175: */
176: public Collection getDefaultExistenceChecks(String docTypeName) {
177:
178: Collection defaultExistenceChecks = null;
179:
180: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
181: if (entry != null) {
182: defaultExistenceChecks = entry.getDefaultExistenceChecks();
183: }
184:
185: return defaultExistenceChecks;
186: }
187:
188: /**
189: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getApplyApcRules(java.lang.Class)
190: */
191: public Collection getApplyApcRules(Class businessObjectClass) {
192: return getApplyApcRules(getDocumentTypeName(businessObjectClass));
193: }
194:
195: /**
196: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getApplyApcRules(java.lang.String)
197: */
198: public Collection getApplyApcRules(String docTypeName) {
199:
200: Collection apcRules = null;
201:
202: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
203: if (entry != null) {
204: apcRules = entry.getApcRules();
205: }
206:
207: return apcRules;
208: }
209:
210: /**
211: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getLockingKeys(java.lang.String)
212: */
213: public List getLockingKeys(String docTypeName) {
214: List lockingKeys = null;
215:
216: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
217: if (entry != null) {
218: lockingKeys = entry.getLockingKeyFieldnames();
219: }
220:
221: return lockingKeys;
222: }
223:
224: /**
225: * @param dataDictionaryService
226: */
227: public void setDataDictionaryService(
228: DataDictionaryService dataDictionaryService) {
229: this .dataDictionaryService = dataDictionaryService;
230: }
231:
232: /**
233: * @return
234: */
235: public DataDictionary getDataDictionary() {
236: return this .dataDictionaryService.getDataDictionary();
237: }
238:
239: /**
240: * @param docTypeName
241: * @return
242: */
243: public MaintenanceDocumentEntry getMaintenanceDocumentEntry(
244: String docTypeName) {
245: if (StringUtils.isBlank(docTypeName)) {
246: throw new IllegalArgumentException(
247: "invalid (blank) docTypeName");
248: }
249:
250: MaintenanceDocumentEntry entry = (MaintenanceDocumentEntry) getDataDictionary()
251: .getDocumentEntry(docTypeName);
252: return entry;
253: }
254:
255: private MaintenanceDocumentEntry getMaintenanceDocumentEntry(
256: Class businessObjectClass) {
257: if (businessObjectClass == null) {
258: throw new IllegalArgumentException(
259: "invalid (blank) businessObjectClass");
260: }
261:
262: MaintenanceDocumentEntry entry = getDataDictionary()
263: .getMaintenanceDocumentEntryForBusinessObjectClass(
264: businessObjectClass);
265: return entry;
266: }
267:
268: /**
269: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getFieldDefaultValue(java.lang.Class, java.lang.String)
270: */
271: public String getFieldDefaultValue(Class boClass, String fieldName) {
272:
273: // input parameter validation
274: if (boClass == null) {
275: throw new IllegalArgumentException(
276: "The boClass parameter value specified was "
277: + "null. A valid class representing the boClass must "
278: + "be specified.");
279: }
280:
281: // call the twin
282: return getFieldDefaultValue(getDocumentTypeName(boClass),
283: fieldName);
284: }
285:
286: /**
287: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getFieldDefaultValue(java.lang.String, java.lang.String)
288: */
289: public String getFieldDefaultValue(String docTypeName,
290: String fieldName) {
291:
292: // input parameter validation
293: if (StringUtils.isBlank(docTypeName)) {
294: throw new IllegalArgumentException(
295: "The docTypeName parameter value specified was "
296: + "blank, whitespace, or null. A valid string representing the docTypeName must "
297: + "be specified.");
298: }
299: if (StringUtils.isBlank(fieldName)) {
300: throw new IllegalArgumentException(
301: "The fieldName parameter value specified was "
302: + "blank, whitespace, or null. A valid string representing the fieldName must "
303: + "be specified.");
304: }
305:
306: // walk through the sections
307: List sections = getMaintainableSections(docTypeName);
308: for (Iterator sectionIterator = sections.iterator(); sectionIterator
309: .hasNext();) {
310: MaintainableSectionDefinition section = (MaintainableSectionDefinition) sectionIterator
311: .next();
312:
313: // walk through the fields
314: Collection fields = section.getMaintainableItems();
315: String defaultValue = getFieldDefaultValue(fields,
316: fieldName);
317: // need to keep trying sections until a match is found
318: if (defaultValue != null) {
319: return defaultValue;
320: }
321: }
322: return null;
323: }
324:
325: private String getFieldDefaultValue(Collection maintainableFields,
326: String fieldName) {
327: for (Iterator iterator = maintainableFields.iterator(); iterator
328: .hasNext();) {
329: MaintainableItemDefinition item = (MaintainableItemDefinition) iterator
330: .next();
331: // only check fields...skip subcollections
332: if (item instanceof MaintainableFieldDefinition) {
333:
334: MaintainableFieldDefinition field = (MaintainableFieldDefinition) item;
335:
336: // if the field name matches
337: if (field.getName().endsWith(fieldName)) {
338:
339: // preferentially take the raw default value
340: if (StringUtils.isNotBlank(field.getDefaultValue())) {
341: return field.getDefaultValue();
342: }
343:
344: // take the valuefinder
345: else if (field.getDefaultValueFinderClass() != null) {
346:
347: // attempt to get an instance of the defaultValueFinderClass
348: ValueFinder valueFinder = null;
349: try {
350: valueFinder = (ValueFinder) field
351: .getDefaultValueFinderClass()
352: .newInstance();
353: } catch (Exception e) {
354: LOG
355: .info(
356: "Exception obtaining valueFinder for collection field default value",
357: e);
358: valueFinder = null;
359: }
360:
361: // get the value
362: if (valueFinder != null) {
363: return valueFinder.getValue();
364: }
365: }
366: // if we found the field, but no default anything, then we're done
367: else {
368: return null;
369: }
370: }
371: }
372: }
373: return null;
374: }
375:
376: /**
377: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getCollectionFieldDefaultValue(java.lang.String,
378: * java.lang.String, java.lang.String)
379: */
380: public String getCollectionFieldDefaultValue(String docTypeName,
381: String collectionName, String fieldName) {
382: // input parameter validation
383: if (StringUtils.isBlank(docTypeName)) {
384: throw new IllegalArgumentException(
385: "The docTypeName parameter value specified was blank, whitespace, or null. A valid string representing the docTypeName must be specified.");
386: }
387: if (StringUtils.isBlank(fieldName)) {
388: throw new IllegalArgumentException(
389: "The fieldName parameter value specified was blank, whitespace, or null. A valid string representing the fieldName must be specified.");
390: }
391: if (StringUtils.isBlank(collectionName)) {
392: throw new IllegalArgumentException(
393: "The collectionName parameter value specified was null. A valid string representing the collectionName must be specified.");
394: }
395:
396: MaintainableCollectionDefinition coll = getMaintainableCollection(
397: docTypeName, collectionName);
398: if (coll != null) {
399: Collection collectionFields = coll.getMaintainableFields();
400: return getFieldDefaultValue(collectionFields, fieldName);
401: }
402: return null;
403: }
404:
405: /**
406: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getAllowsCopy(MaintenanceDocument)
407: */
408: public Boolean getAllowsCopy(MaintenanceDocument document) {
409: Boolean allowsCopy = null;
410: if (document != null) {
411: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(document
412: .getNewMaintainableObject().getBoClass());
413: if (entry != null) {
414: allowsCopy = Boolean.valueOf(entry.getAllowsCopy());
415: }
416: }
417:
418: return allowsCopy;
419: }
420:
421: /**
422: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#getAllowsNewOrCopy(java.lang.String)
423: */
424: public Boolean getAllowsNewOrCopy(String docTypeName) {
425: Boolean allowsNewOrCopy = null;
426:
427: if (docTypeName != null) {
428: MaintenanceDocumentEntry entry = getMaintenanceDocumentEntry(docTypeName);
429: if (entry != null) {
430: allowsNewOrCopy = Boolean.valueOf(entry
431: .getAllowsNewOrCopy());
432: }
433: }
434:
435: return allowsNewOrCopy;
436: }
437:
438: public MaintainableItemDefinition getMaintainableItem(
439: String docTypeName, String itemName) {
440: // input parameter validation
441: if (StringUtils.isBlank(docTypeName)) {
442: throw new IllegalArgumentException(
443: "The docTypeName parameter value specified was "
444: + "blank, whitespace, or null. A valid string representing the docTypeName must "
445: + "be specified.");
446: }
447: if (StringUtils.isBlank(itemName)) {
448: throw new IllegalArgumentException(
449: "The itemName parameter value specified was "
450: + "blank, whitespace, or null. A valid string representing the itemName must "
451: + "be specified.");
452: }
453:
454: // split name for subcollections
455: String[] subItems = {};
456: subItems = StringUtils.split(itemName, ".");
457:
458: // walk through the sections
459: List sections = getMaintainableSections(docTypeName);
460: for (Iterator sectionIterator = sections.iterator(); sectionIterator
461: .hasNext();) {
462: MaintainableSectionDefinition section = (MaintainableSectionDefinition) sectionIterator
463: .next();
464:
465: // walk through the fields
466: Collection fields = section.getMaintainableItems();
467: for (Iterator fieldIterator = fields.iterator(); fieldIterator
468: .hasNext();) {
469: MaintainableItemDefinition item = (MaintainableItemDefinition) fieldIterator
470: .next();
471:
472: if (item.getName().equals(itemName)) {
473: return item;
474: }
475: // if collection check to see if it has sub collections
476: // for now this only allows 1 level (i.e. a.b) it should be expanded at some point
477: if (item instanceof MaintainableCollectionDefinition) {
478: MaintainableCollectionDefinition col = (MaintainableCollectionDefinition) item;
479: if ((subItems.length > 1)
480: && (StringUtils.equals(col.getName(),
481: subItems[0]))) {
482: for (Iterator<MaintainableCollectionDefinition> colIterator = col
483: .getMaintainableCollections()
484: .iterator(); colIterator.hasNext();) {
485: MaintainableCollectionDefinition subCol = (MaintainableCollectionDefinition) colIterator
486: .next();
487: if (subCol.getName().equals(subItems[1])) {
488: return subCol;
489: }
490: }
491: }
492: }
493: }
494: }
495: return null;
496: }
497:
498: public MaintainableFieldDefinition getMaintainableField(
499: String docTypeName, String fieldName) {
500: MaintainableItemDefinition item = getMaintainableItem(
501: docTypeName, fieldName);
502: if (item != null && item instanceof MaintainableFieldDefinition) {
503: return (MaintainableFieldDefinition) item;
504: }
505: return null;
506: }
507:
508: public MaintainableCollectionDefinition getMaintainableCollection(
509: String docTypeName, String collectionName) {
510: // strip brackets as they are not needed to get to collection class
511: // Like the other subcollections changes this currently only supports one sub level
512: if (StringUtils.contains(collectionName, "[")) {
513: collectionName = StringUtils.substringBefore(
514: collectionName, "[")
515: + StringUtils.substringAfter(collectionName, "]");
516: }
517: MaintainableItemDefinition item = getMaintainableItem(
518: docTypeName, collectionName);
519: if (item != null
520: && item instanceof MaintainableCollectionDefinition) {
521: return (MaintainableCollectionDefinition) item;
522: }
523: return null;
524: }
525:
526: public Class getCollectionBusinessObjectClass(String docTypeName,
527: String collectionName) {
528: MaintainableCollectionDefinition coll = getMaintainableCollection(
529: docTypeName, collectionName);
530: if (coll != null) {
531: return coll.getBusinessObjectClass();
532: }
533: return null;
534: }
535:
536: public List<MaintainableCollectionDefinition> getMaintainableCollections(
537: String docTypeName) {
538: ArrayList<MaintainableCollectionDefinition> collections = new ArrayList<MaintainableCollectionDefinition>();
539:
540: // walk through the sections
541: List sections = getMaintainableSections(docTypeName);
542: for (Iterator sectionIterator = sections.iterator(); sectionIterator
543: .hasNext();) {
544: MaintainableSectionDefinition section = (MaintainableSectionDefinition) sectionIterator
545: .next();
546:
547: // walk through the fields
548: Collection fields = section.getMaintainableItems();
549: for (Iterator fieldIterator = fields.iterator(); fieldIterator
550: .hasNext();) {
551: MaintainableItemDefinition item = (MaintainableItemDefinition) fieldIterator
552: .next();
553:
554: if (item instanceof MaintainableCollectionDefinition) {
555: collections
556: .add((MaintainableCollectionDefinition) item);
557: // collections.addAll( getMaintainableCollections( (MaintainableCollectionDefinition)item ) );
558: }
559: }
560: }
561:
562: return collections;
563: }
564:
565: public List<MaintainableCollectionDefinition> getMaintainableCollections(
566: MaintainableCollectionDefinition parentCollection) {
567: ArrayList<MaintainableCollectionDefinition> collections = new ArrayList<MaintainableCollectionDefinition>();
568:
569: // walk through the sections
570: Collection<MaintainableCollectionDefinition> colls = parentCollection
571: .getMaintainableCollections();
572: for (MaintainableCollectionDefinition coll : colls) {
573: collections.add(coll);
574: collections.addAll(getMaintainableCollections(coll));
575: }
576:
577: return collections;
578: }
579:
580: /**
581: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#validateMaintenanceRequiredFields(org.kuali.core.document.MaintenanceDocument)
582: */
583: public void validateMaintenanceRequiredFields(
584: MaintenanceDocument document) {
585: Maintainable newMaintainableObject = document
586: .getNewMaintainableObject();
587: if (newMaintainableObject == null) {
588: LOG.error("New maintainable is null");
589: throw new RuntimeException("New maintainable is null");
590: }
591:
592: List<MaintainableSectionDefinition> maintainableSectionDefinitions = getMaintainableSections(getDocumentTypeName(newMaintainableObject
593: .getBoClass()));
594: for (MaintainableSectionDefinition maintainableSectionDefinition : maintainableSectionDefinitions) {
595: for (MaintainableItemDefinition maintainableItemDefinition : maintainableSectionDefinition
596: .getMaintainableItems()) {
597: // validate fields
598: if (maintainableItemDefinition instanceof MaintainableFieldDefinition) {
599: validateMaintainableFieldRequiredFields(
600: (MaintainableFieldDefinition) maintainableItemDefinition,
601: newMaintainableObject.getBusinessObject(),
602: maintainableItemDefinition.getName());
603: }
604: // validate collections
605: else if (maintainableItemDefinition instanceof MaintainableCollectionDefinition) {
606: validateMaintainableCollectionsRequiredFields(
607: newMaintainableObject.getBusinessObject(),
608: (MaintainableCollectionDefinition) maintainableItemDefinition);
609: }
610: }
611: }
612: }
613:
614: /**
615: * generates error message if a field is marked as required but is not filled in
616: *
617: * @param maintainableFieldDefinition
618: * @param businessObject
619: * @param fieldName
620: */
621: private void validateMaintainableFieldRequiredFields(
622: MaintainableFieldDefinition maintainableFieldDefinition,
623: PersistableBusinessObject businessObject, String fieldName) {
624:
625: if (StringUtils.isBlank(fieldName)) {
626: throw new IllegalArgumentException(
627: "invalid fieldName parameter.");
628: }
629: // if required check we have a value for this field
630: if (maintainableFieldDefinition.isRequired()
631: && !maintainableFieldDefinition.isReadOnly()) {
632: try {
633: Object obj = ObjectUtils.getNestedValue(businessObject,
634: fieldName);
635:
636: if (obj == null || StringUtils.isBlank(obj.toString())) {
637: String attributeLabel = dataDictionaryService
638: .getAttributeLabel(businessObject
639: .getClass(), fieldName);
640: String shortLabel = dataDictionaryService
641: .getAttributeShortLabel(businessObject
642: .getClass(), fieldName);
643: GlobalVariables.getErrorMap().putError(fieldName,
644: RiceKeyConstants.ERROR_REQUIRED,
645: attributeLabel + " (" + shortLabel + ")");
646: }
647: } catch (Exception ex) {
648: LOG
649: .error(
650: "unable to read property during doc required field checks",
651: ex);
652: }
653: }
654: }
655:
656: private MaintainableCollectionDefinition getCollectionDefinition(
657: String docTypeName, String collectionName) {
658: String currentCollection = StringUtils.substringBefore(
659: collectionName, ".");
660: String nestedCollections = StringUtils.substringAfter(
661: collectionName, ".");
662: // strip off any array indexes
663: currentCollection = StringUtils.substringBefore(collectionName,
664: "[");
665: // loop over all sections to find this collection
666: List<MaintainableSectionDefinition> maintainableSectionDefinitions = getMaintainableSections(docTypeName);
667: for (MaintainableSectionDefinition maintainableSectionDefinition : maintainableSectionDefinitions) {
668: for (MaintainableItemDefinition maintainableItemDefinition : maintainableSectionDefinition
669: .getMaintainableItems()) {
670: if (maintainableItemDefinition instanceof MaintainableCollectionDefinition
671: && maintainableItemDefinition.getName().equals(
672: currentCollection)) {
673: if (StringUtils.isBlank(nestedCollections)) {
674: return (MaintainableCollectionDefinition) maintainableItemDefinition;
675: } else {
676: return getCollectionDefinition(
677: (MaintainableCollectionDefinition) maintainableItemDefinition,
678: nestedCollections);
679: }
680: }
681: }
682: }
683: return null;
684: }
685:
686: private MaintainableCollectionDefinition getCollectionDefinition(
687: MaintainableCollectionDefinition collectionDef,
688: String collectionName) {
689: String currentCollection = StringUtils.substringBefore(
690: collectionName, ".");
691: String nestedCollections = StringUtils.substringAfter(
692: collectionName, ".");
693: // strip off any array indexes
694: currentCollection = StringUtils.substringBefore(collectionName,
695: "[");
696: // loop over all nested collections
697: for (MaintainableCollectionDefinition maintainableCollectionDefinition : collectionDef
698: .getMaintainableCollections()) {
699: if (maintainableCollectionDefinition.getName().equals(
700: collectionName)) {
701: if (StringUtils.isBlank(nestedCollections)) {
702: return maintainableCollectionDefinition;
703: } else {
704: return getCollectionDefinition(
705: maintainableCollectionDefinition,
706: nestedCollections);
707: }
708: }
709: }
710: return null;
711: }
712:
713: public void validateMaintainableCollectionsAddLineRequiredFields(
714: MaintenanceDocument document,
715: PersistableBusinessObject businessObject,
716: String collectionName) {
717: MaintainableCollectionDefinition def = getCollectionDefinition(
718: getDocumentTypeName(businessObject.getClass()),
719: collectionName);
720: if (def != null) {
721: validateMaintainableCollectionsAddLineRequiredFields(
722: document, businessObject, collectionName, def, 0);
723: }
724: }
725:
726: /**
727: * calls code to generate error messages if maintainableFields within any collections or sub-collections are marked as required
728: *
729: * @param document
730: * @param businessObject
731: * @param collectionName
732: * @param maintainableCollectionDefinition
733: * @param depth
734: */
735: private void validateMaintainableCollectionsAddLineRequiredFields(
736: MaintenanceDocument document,
737: PersistableBusinessObject businessObject,
738: String collectionName,
739: MaintainableCollectionDefinition maintainableCollectionDefinition,
740: int depth) {
741: if (depth == 0) {
742: GlobalVariables.getErrorMap().addToErrorPath("add");
743: }
744: // validate required fields on fields withing collection definition
745: PersistableBusinessObject element = document
746: .getNewMaintainableObject().getNewCollectionLine(
747: collectionName);
748: GlobalVariables.getErrorMap().addToErrorPath(collectionName);
749: for (MaintainableFieldDefinition maintainableFieldDefinition : maintainableCollectionDefinition
750: .getMaintainableFields()) {
751: final String fieldName = maintainableFieldDefinition
752: .getName();
753: validateMaintainableFieldRequiredFields(
754: maintainableFieldDefinition, element, fieldName);
755:
756: }
757:
758: GlobalVariables.getErrorMap().removeFromErrorPath(
759: collectionName);
760: if (depth == 0) {
761: GlobalVariables.getErrorMap().removeFromErrorPath("add");
762: }
763: }
764:
765: /**
766: * calls code to generate error messages if maintainableFields within any collections or sub-collections are marked as required
767: *
768: * @param businessObject
769: * @param maintainableCollectionDefinition
770: */
771: private void validateMaintainableCollectionsRequiredFields(
772: PersistableBusinessObject businessObject,
773: MaintainableCollectionDefinition maintainableCollectionDefinition) {
774: final String collectionName = maintainableCollectionDefinition
775: .getName();
776:
777: // validate required fields on fields withing collection definition
778: Collection<PersistableBusinessObject> collection = (Collection) ObjectUtils
779: .getPropertyValue(businessObject, collectionName);
780: if (collection != null && !collection.isEmpty()) {
781: for (MaintainableFieldDefinition maintainableFieldDefinition : maintainableCollectionDefinition
782: .getMaintainableFields()) {
783: int pos = 0;
784: final String fieldName = maintainableFieldDefinition
785: .getName();
786: for (PersistableBusinessObject element : collection) {
787: String parentName = collectionName + "[" + (pos++)
788: + "]";
789: GlobalVariables.getErrorMap().addToErrorPath(
790: parentName);
791: validateMaintainableFieldRequiredFields(
792: maintainableFieldDefinition, element,
793: fieldName);
794: GlobalVariables.getErrorMap().removeFromErrorPath(
795: parentName);
796: }
797: }
798:
799: // recursivley validate required fields on subcollections
800: GlobalVariables.getErrorMap()
801: .addToErrorPath(collectionName);
802: for (MaintainableCollectionDefinition nestedMaintainableCollectionDefinition : maintainableCollectionDefinition
803: .getMaintainableCollections()) {
804: for (PersistableBusinessObject element : collection) {
805: validateMaintainableCollectionsRequiredFields(
806: element,
807: nestedMaintainableCollectionDefinition);
808: }
809: }
810: GlobalVariables.getErrorMap().removeFromErrorPath(
811: collectionName);
812: }
813: }
814:
815: /**
816: * default implementation checks for duplicats based on keys of objects only
817: *
818: * @see org.kuali.core.service.MaintenanceDocumentDictionaryService#validateMaintainableCollectionsForDuplicateEntries(org.kuali.core.document.MaintenanceDocument)
819: */
820: public void validateMaintainableCollectionsForDuplicateEntries(
821: MaintenanceDocument document) {
822: Maintainable newMaintainableObject = document
823: .getNewMaintainableObject();
824: if (newMaintainableObject == null) {
825: LOG.error("New maintainable is null");
826: throw new RuntimeException("New maintainable is null");
827: }
828:
829: List<MaintainableSectionDefinition> maintainableSectionDefinitions = getMaintainableSections(getDocumentTypeName(newMaintainableObject
830: .getBoClass()));
831: for (MaintainableSectionDefinition maintainableSectionDefinition : maintainableSectionDefinitions) {
832: for (MaintainableItemDefinition maintainableItemDefinition : maintainableSectionDefinition
833: .getMaintainableItems()) {
834: // validate collections
835: if (maintainableItemDefinition instanceof MaintainableCollectionDefinition) {
836: validateMaintainableCollectionsForDuplicateEntries(
837: newMaintainableObject.getBusinessObject(),
838: (MaintainableCollectionDefinition) maintainableItemDefinition);
839: }
840: }
841: }
842: }
843:
844: /**
845: * recursivly checks collections for duplicate entries based on key valuse
846: *
847: * @param businessObject
848: * @param maintainableCollectionDefinition
849: */
850: private void validateMaintainableCollectionsForDuplicateEntries(
851: PersistableBusinessObject businessObject,
852: MaintainableCollectionDefinition maintainableCollectionDefinition) {
853: final String collectionName = maintainableCollectionDefinition
854: .getName();
855:
856: if (maintainableCollectionDefinition.dissalowDuplicateKey()) {
857: final Class maintainableBusinessObjectClass = businessObject
858: .getClass();
859: // validate that no duplicates based on keys exist
860: Collection<PersistableBusinessObject> collection = (Collection) ObjectUtils
861: .getPropertyValue(businessObject, collectionName);
862: if (collection != null && !collection.isEmpty()) {
863: final String propertyName = maintainableCollectionDefinition
864: .getAttributeToHighlightOnDuplicateKey();
865: // get collection label for dd
866: final String label = dataDictionaryService
867: .getCollectionLabel(
868: maintainableBusinessObjectClass,
869: collectionName);
870: final String shortLabel = dataDictionaryService
871: .getCollectionShortLabel(
872: maintainableBusinessObjectClass,
873: collectionName);
874: int pos = 0;
875: for (PersistableBusinessObject element : collection) {
876: String pathToElement = collectionName + "["
877: + (pos++) + "]";
878: if (ObjectUtils.countObjectsWithIdentitcalKey(
879: collection, element) > 1) {
880: GlobalVariables.getErrorMap().addToErrorPath(
881: pathToElement);
882: GlobalVariables
883: .getErrorMap()
884: .putError(
885: propertyName,
886: RiceKeyConstants.ERROR_DUPLICATE_ELEMENT,
887: new String[] { label,
888: shortLabel });
889: GlobalVariables.getErrorMap()
890: .removeFromErrorPath(pathToElement);
891: }
892: }
893:
894: // recursivley check for duplicate entries on subcollections
895: GlobalVariables.getErrorMap().addToErrorPath(
896: collectionName);
897: for (MaintainableCollectionDefinition nestedMaintainableCollectionDefinition : maintainableCollectionDefinition
898: .getMaintainableCollections()) {
899: for (PersistableBusinessObject element : collection) {
900: validateMaintainableCollectionsForDuplicateEntries(
901: element,
902: nestedMaintainableCollectionDefinition);
903: }
904: }
905: GlobalVariables.getErrorMap().removeFromErrorPath(
906: collectionName);
907:
908: }
909: }
910: }
911:
912: }
|