001 /** 002 * Copyright 2005-2014 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.krad.datadictionary.validation.result; 017 018 import org.kuali.rice.krad.datadictionary.validation.AttributeValueReader; 019 import org.kuali.rice.krad.datadictionary.validation.ErrorLevel; 020 import org.kuali.rice.krad.datadictionary.validation.ValidationUtils; 021 022 import java.util.Iterator; 023 import java.util.LinkedHashMap; 024 import java.util.Map; 025 026 /** 027 * DictionaryValidationResult holds dictionary validation results 028 * 029 * @author Kuali Rice Team (rice.collab@kuali.org) 030 */ 031 public class DictionaryValidationResult implements Iterable<ConstraintValidationResult> { 032 033 private Map<String, EntryValidationResult> entryValidationResultMap; 034 private ErrorLevel errorLevel; 035 036 private int numberOfErrors; 037 private int numberOfWarnings; 038 039 private Iterator<ConstraintValidationResult> iterator; 040 041 /** 042 * default constructor 043 */ 044 public DictionaryValidationResult() { 045 this.entryValidationResultMap = new LinkedHashMap<String, EntryValidationResult>(); 046 this.errorLevel = ErrorLevel.ERROR; 047 this.numberOfErrors = 0; 048 this.numberOfWarnings = 0; 049 } 050 051 /** 052 * adds the result of a constraint validation performed on an attribute 053 * 054 * @param attributeValueReader - provides access to the attribute being validated 055 * @param constraintValidationResult - the result of processing a constraint 056 */ 057 public void addConstraintValidationResult(AttributeValueReader attributeValueReader, 058 ConstraintValidationResult constraintValidationResult) { 059 060 // Don't bother to store this if the error level of the constraint validation result is lower than the level this dictionary validation result is tracking 061 if (constraintValidationResult.getStatus().getLevel() < errorLevel.getLevel()) { 062 return; 063 } 064 065 switch (constraintValidationResult.getStatus()) { 066 case ERROR: 067 numberOfErrors++; 068 break; 069 case WARN: 070 numberOfWarnings++; 071 break; 072 default: 073 // Do nothing 074 } 075 076 // Give the constraint a chance to override the entry and attribute name - important if the attribute name is not the same as the one in the attribute value reader! 077 String entryName = constraintValidationResult.getEntryName(); 078 String attributeName = constraintValidationResult.getAttributeName(); 079 String attributePath = constraintValidationResult.getAttributePath(); 080 081 if (entryName == null) { 082 entryName = attributeValueReader.getEntryName(); 083 } 084 085 if (attributeName == null) { 086 attributeName = attributeValueReader.getAttributeName(); 087 } 088 089 if (attributePath == null) { 090 attributePath = attributeValueReader.getPath(); 091 } 092 093 constraintValidationResult.setEntryName(entryName); 094 constraintValidationResult.setAttributeName(attributeName); 095 constraintValidationResult.setAttributePath(attributePath); 096 097 String entryKey = getEntryValidationResultKey(entryName, attributePath); 098 getEntryValidationResult(entryKey).getAttributeValidationResult(attributeName).addConstraintValidationResult( 099 constraintValidationResult); 100 } 101 102 /** 103 * provides information used to display error messages to the user concerning a constraint validation 104 * 105 * @param attributeValueReader - provides access to the attribute being validated 106 * @param constraintName - a descriptive name of the current constraint processor 107 * @param errorKey - a key used to fetch an informational message to show the user 108 * @param errorParameters - parameters to substitute into the informational message 109 * @return a constraint validation result encompassing the information provided 110 */ 111 public ConstraintValidationResult addError(AttributeValueReader attributeValueReader, String constraintName, 112 String errorKey, String... errorParameters) { 113 ConstraintValidationResult constraintValidationResult = getConstraintValidationResult( 114 attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), 115 attributeValueReader.getPath(), constraintName); 116 constraintValidationResult.setError(errorKey, errorParameters); 117 numberOfErrors++; 118 return constraintValidationResult; 119 } 120 121 /** 122 * provides information used to display error messages to the user concerning a constraint validation 123 * 124 * @param constraintLabelKey - a key used to fetch an information message to show the user 125 * @param attributeValueReader - provides access to the attribute being validated 126 * @param constraintName - a descriptive name of the current constraint processor 127 * @param errorKey - a key used to fetch an error message to show the user 128 * @param errorParameters - parameters to substitute into the error message 129 * @return a constraint validation result encompassing the information provided 130 */ 131 public ConstraintValidationResult addError(String constraintLabelKey, AttributeValueReader attributeValueReader, 132 String constraintName, String errorKey, String... errorParameters) { 133 ConstraintValidationResult constraintValidationResult = getConstraintValidationResult( 134 attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), 135 attributeValueReader.getPath(), constraintName); 136 constraintValidationResult.setError(errorKey, errorParameters); 137 constraintValidationResult.setConstraintLabelKey(constraintLabelKey); 138 numberOfErrors++; 139 return constraintValidationResult; 140 } 141 142 /** 143 * provides information used to display warning messages to the user concerning a constraint validation 144 * 145 * @param attributeValueReader - provides access to the attribute being validated 146 * @param constraintName - a descriptive name of the current constraint processor 147 * @param errorKey - a key used to fetch a warning message to show the user 148 * @param errorParameters - parameters to substitute into the warning message 149 * @return a constraint validation result encompassing the information provided 150 */ 151 public ConstraintValidationResult addWarning(AttributeValueReader attributeValueReader, String constraintName, 152 String errorKey, String... errorParameters) { 153 if (errorLevel.getLevel() > ErrorLevel.WARN.getLevel()) { 154 return new ConstraintValidationResult(constraintName, ErrorLevel.WARN); 155 } 156 157 ConstraintValidationResult constraintValidationResult = getConstraintValidationResult( 158 attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), 159 attributeValueReader.getPath(), constraintName); 160 constraintValidationResult.setWarning(errorKey, errorParameters); 161 numberOfWarnings++; 162 return constraintValidationResult; 163 } 164 165 /** 166 * indicates that a constraint validation has succeeded 167 * 168 * @param attributeValueReader - provides access to the attribute being validated 169 * @param constraintName - a descriptive name of the current constraint processor 170 * @return a constraint validation result encompassing the information provided 171 */ 172 public ConstraintValidationResult addSuccess(AttributeValueReader attributeValueReader, String constraintName) { 173 if (errorLevel.getLevel() > ErrorLevel.OK.getLevel()) { 174 return new ConstraintValidationResult(constraintName, ErrorLevel.OK); 175 } 176 177 return getConstraintValidationResult(attributeValueReader.getEntryName(), 178 attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName); 179 } 180 181 /** 182 * indicates that a constraint validation has been skipped 183 * 184 * @param attributeValueReader - provides access to the attribute being validated 185 * @param constraintName - a descriptive name of the current constraint processor 186 * @return a constraint validation result encompassing the information provided 187 */ 188 public ConstraintValidationResult addSkipped(AttributeValueReader attributeValueReader, String constraintName) { 189 if (errorLevel.getLevel() > ErrorLevel.OK.getLevel()) { 190 return new ConstraintValidationResult(constraintName, ErrorLevel.INAPPLICABLE); 191 } 192 193 ConstraintValidationResult constraintValidationResult = getConstraintValidationResult( 194 attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), 195 attributeValueReader.getPath(), constraintName); 196 constraintValidationResult.setStatus(ErrorLevel.INAPPLICABLE); 197 return constraintValidationResult; 198 } 199 200 /** 201 * indicates that a constraint validation processing has been skipped 202 * 203 * @param attributeValueReader - provides access to the attribute being validated 204 * @param constraintName - a descriptive name of the current constraint processor 205 * @return a constraint validation result encompassing the information provided 206 */ 207 public ConstraintValidationResult addNoConstraint(AttributeValueReader attributeValueReader, 208 String constraintName) { 209 if (errorLevel.getLevel() > ErrorLevel.OK.getLevel()) { 210 return new ConstraintValidationResult(constraintName, ErrorLevel.NOCONSTRAINT); 211 } 212 213 ConstraintValidationResult constraintValidationResult = getConstraintValidationResult( 214 attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), 215 attributeValueReader.getPath(), constraintName); 216 constraintValidationResult.setStatus(ErrorLevel.NOCONSTRAINT); 217 return constraintValidationResult; 218 } 219 220 /** 221 * gets an iterator over the various {@code ConstraintValidationResult}'s contained in this class 222 * 223 * @return an iterator 224 */ 225 public Iterator<ConstraintValidationResult> iterator() { 226 227 iterator = new Iterator<ConstraintValidationResult>() { 228 229 private Iterator<EntryValidationResult> entryIterator; 230 private Iterator<AttributeValidationResult> attributeIterator; 231 private Iterator<ConstraintValidationResult> constraintIterator; 232 233 @Override 234 public boolean hasNext() { 235 Iterator<ConstraintValidationResult> currentConstraintIterator = getCurrentConstraintIterator(); 236 return currentConstraintIterator != null && currentConstraintIterator.hasNext(); 237 } 238 239 @Override 240 public ConstraintValidationResult next() { 241 Iterator<ConstraintValidationResult> currentConstraintIterator = getCurrentConstraintIterator(); 242 return currentConstraintIterator != null ? currentConstraintIterator.next() : null; 243 } 244 245 @Override 246 public void remove() { 247 throw new RuntimeException("Can't remove from this iterator!"); 248 } 249 250 private Iterator<ConstraintValidationResult> getCurrentConstraintIterator() { 251 if (constraintIterator == null || constraintIterator.hasNext() == false) { 252 Iterator<AttributeValidationResult> currentAttributeIterator = getCurrentAttributeIterator(); 253 if (currentAttributeIterator != null && currentAttributeIterator.hasNext()) { 254 AttributeValidationResult currentAttributeValidationResult = currentAttributeIterator.next(); 255 constraintIterator = currentAttributeValidationResult.iterator(); 256 } 257 } 258 return constraintIterator; 259 } 260 261 private Iterator<AttributeValidationResult> getCurrentAttributeIterator() { 262 if (attributeIterator == null || attributeIterator.hasNext() == false) { 263 Iterator<EntryValidationResult> currentEntryIterator = getCurrentEntryIterator(); 264 if (currentEntryIterator != null && currentEntryIterator.hasNext()) { 265 EntryValidationResult currentEntryValidationResult = currentEntryIterator.next(); 266 attributeIterator = currentEntryValidationResult.iterator(); 267 } 268 } 269 return attributeIterator; 270 } 271 272 private Iterator<EntryValidationResult> getCurrentEntryIterator() { 273 if (entryIterator == null) // || entryIterator.hasNext() == false) 274 { 275 entryIterator = entryValidationResultMap.values().iterator(); 276 } 277 return entryIterator; 278 } 279 280 }; 281 282 return iterator; 283 } 284 285 /** 286 * gets an entry validation result for the given {@code entryName} 287 * 288 * @param entryName - the name that the data dictionary uses to store metadata about the attribute 289 * @return the existing {@code EntryValidationResult} for the given {@code entryName} or creates a new one if 290 * absent 291 */ 292 protected EntryValidationResult getEntryValidationResult(String entryName) { 293 EntryValidationResult entryValidationResult = entryValidationResultMap.get(entryName); 294 if (entryValidationResult == null) { 295 entryValidationResult = new EntryValidationResult(entryName); 296 entryValidationResultMap.put(entryName, entryValidationResult); 297 } 298 return entryValidationResult; 299 } 300 301 /** 302 * composes a {@code ConstraintValidationResult} from the parameters given 303 * 304 * @param entryName - the name that the data dictionary uses to store metadata about the attribute 305 * @param attributeName - the attribute name 306 * @param attributePath - a string representation of specifically which attribute (at some depth) is being accessed 307 * @param constraintName - a descriptive name of the current constraint processor 308 * @return validation result 309 */ 310 private ConstraintValidationResult getConstraintValidationResult(String entryName, String attributeName, 311 String attributePath, String constraintName) { 312 String entryKey = getEntryValidationResultKey(entryName, attributePath); 313 ConstraintValidationResult constraintValidationResult = getEntryValidationResult(entryKey) 314 .getAttributeValidationResult(attributeName).getConstraintValidationResult(constraintName); 315 constraintValidationResult.setEntryName(entryName); 316 constraintValidationResult.setAttributeName(attributeName); 317 constraintValidationResult.setAttributePath(attributePath); 318 return constraintValidationResult; 319 } 320 321 /** 322 * gets the key to the {@link EntryValidationResult} entry in the EntryValidationResultMap 323 * 324 * <p>Most cases entry key will be the entryName, unless the attribute is part of a collection, 325 * in which case entry key will be suffixed with index of attribute's parent item.</p> 326 * 327 * @param entryName - the name that the data dictionary uses to store metadata about the attribute 328 * @param attributePath - a string representation of specifically which attribute (at some depth) is being accessed 329 * @return a key used to fetch an associated {@code EntryValidationResult} 330 */ 331 private String getEntryValidationResultKey(String entryName, String attributePath) { 332 if (attributePath.contains("[")) { 333 return entryName + "[" + ValidationUtils.getLastPathIndex(attributePath) + "]"; 334 } 335 return entryName; 336 } 337 338 /** 339 * @return the errorLevel 340 */ 341 public ErrorLevel getErrorLevel() { 342 return this.errorLevel; 343 } 344 345 /** 346 * @param errorLevel the errorLevel to set 347 */ 348 public void setErrorLevel(ErrorLevel errorLevel) { 349 this.errorLevel = errorLevel; 350 } 351 352 /** 353 * @return the numberOfErrors 354 */ 355 public int getNumberOfErrors() { 356 return this.numberOfErrors; 357 } 358 359 /** 360 * @return the numberOfWarnings 361 */ 362 public int getNumberOfWarnings() { 363 return this.numberOfWarnings; 364 } 365 366 }