001 /*
002 * Copyright 2011 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.kfs.sys.document.validation.impl;
017
018 import java.util.Collection;
019 import java.util.Iterator;
020
021 import org.kuali.kfs.sys.document.validation.Validation;
022 import org.kuali.kfs.sys.document.validation.event.AttributedDocumentEvent;
023 import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
024 import org.kuali.rice.kns.util.GlobalVariables;
025 import org.kuali.rice.kns.util.ObjectUtils;
026
027 /**
028 * A validation that runs a list of child validations over each member of a collection.
029 */
030 public class CollectionValidation extends CompositeValidation {
031 protected String collectionProperty;
032
033 /**
034 * Iterates over each member of the collection, which is assumed to be the property of the validation event named by the given collectionProperty
035 * @see org.kuali.kfs.sys.document.validation.impl.CompositeValidation#validate(java.lang.Object[])
036 */
037 public boolean validate(AttributedDocumentEvent event) {
038 boolean result = true;
039
040 if (collectionProperty == null) {
041 throw new IllegalStateException("collectionProperty must not be null");
042 }
043
044 Iterator iter = getCollection(event).iterator();
045
046 // hold on to any existing iteration subject until after we're done doing our thing
047 Object parentIterationSubject = event.getIterationSubject();
048
049 int count = 0;
050 while (iter.hasNext()) {
051 result &= validateEachObject(event, iter.next(), count);
052 count += 1;
053 }
054
055 event.setIterationSubject(parentIterationSubject); // or back to null if the event didn't have an iteration subject in the first place
056
057 return result;
058 }
059
060 /**
061 * Validates each object in the collection
062 * @param event the event to validate against
063 * @param objectToValidate the object from the collection which is being validated
064 * @return true if object passed all child sub-validations, false otherwise
065 */
066 protected boolean validateEachObject(AttributedDocumentEvent event, Object objectToValidate, int count) {
067 boolean result = true;
068 String errorPath = buildPropertyName(count);
069 GlobalVariables.getMessageMap().addToErrorPath(errorPath);
070 boolean currentResult = true;
071 event.setIterationSubject(objectToValidate);
072 for (Validation validation: getValidations()) {
073 currentResult = validation.stageValidation(event);
074 result &= currentResult;
075 if (!currentResult && validation.shouldQuitOnFail()) {
076 break;
077 }
078 }
079 GlobalVariables.getMessageMap().removeFromErrorPath(errorPath);
080 return result;
081 }
082
083 /**
084 * Here's a hack for all my homies: this method builds the property name of a specific item in a collection by chopping the presumed "s" at the end of collectionProperties,
085 * and then attaches array/list syntax to it to hold the count. It'll work for most stuff, won't it?
086 * @params count the count of the current item in the collection
087 * @return
088 */
089 protected String buildPropertyName(int count) {
090 return new StringBuilder().append(collectionProperty.substring(0, collectionProperty.length()-1)).append('[').append(count).append(']').toString();
091 }
092
093 /**
094 * Based on the collection property, finds the events
095 * @param event
096 * @return
097 */
098 protected Collection getCollection(KualiDocumentEvent event) {
099 return (Collection)ObjectUtils.getPropertyValue(event, collectionProperty);
100 }
101
102 /**
103 * Gets the collectionProperty attribute.
104 * @return Returns the collectionProperty.
105 */
106 public String getCollectionProperty() {
107 return collectionProperty;
108 }
109
110 /**
111 * Sets the collectionProperty attribute value.
112 * @param collectionProperty The collectionProperty to set.
113 */
114 public void setCollectionProperty(String collectionProperty) {
115 this.collectionProperty = collectionProperty;
116 }
117 }