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 }