View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.datadictionary.validation.result;
17  
18  import org.kuali.rice.krad.datadictionary.validation.AttributeValueReader;
19  import org.kuali.rice.krad.datadictionary.validation.ErrorLevel;
20  import org.kuali.rice.krad.datadictionary.validation.ValidationUtils;
21  
22  import java.util.Iterator;
23  import java.util.LinkedHashMap;
24  import java.util.Map;
25  
26  /**
27   *  DictionaryValidationResult holds dictionary validation results
28   *
29   * @author Kuali Rice Team (rice.collab@kuali.org) 
30   */
31  public class DictionaryValidationResult implements Iterable<ConstraintValidationResult> {
32  	
33  	private Map<String, EntryValidationResult> entryValidationResultMap;
34  	private ErrorLevel errorLevel;
35  	
36  	private int numberOfErrors;
37  	private int numberOfWarnings;
38  	
39  	private Iterator<ConstraintValidationResult> iterator;
40  
41      /**
42       * default constructor
43       */
44  	public DictionaryValidationResult() {
45  		this.entryValidationResultMap = new LinkedHashMap<String, EntryValidationResult>();
46  		this.errorLevel = ErrorLevel.ERROR;
47  		this.numberOfErrors = 0;
48  		this.numberOfWarnings = 0;
49  	}
50  
51      /**
52       * adds the result of a constraint validation performed on an attribute
53       *
54       * @param attributeValueReader - provides access to the attribute being validated
55       * @param constraintValidationResult - the result of processing a constraint
56       */
57  	public void addConstraintValidationResult(AttributeValueReader attributeValueReader, ConstraintValidationResult constraintValidationResult) {
58  		
59  		// 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
60  		if (constraintValidationResult.getStatus().getLevel() < errorLevel.getLevel())
61  			return;
62  		
63  		switch (constraintValidationResult.getStatus()) {
64  		case ERROR:
65  			numberOfErrors++;
66  			break;
67  		case WARN:
68  			numberOfWarnings++;
69  			break;
70  		default:
71  			// Do nothing
72  		}
73  		
74  		// 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!
75  		String entryName = constraintValidationResult.getEntryName();
76  		String attributeName = constraintValidationResult.getAttributeName();
77  		String attributePath = constraintValidationResult.getAttributePath();
78  		
79  		if (entryName == null){
80  			entryName = attributeValueReader.getEntryName();
81  		}
82  		
83  		if (attributeName == null){
84  			attributeName = attributeValueReader.getAttributeName();
85  		}
86  		
87  		if (attributePath == null){
88  		    attributePath = attributeValueReader.getPath();
89  		}
90  		
91  		constraintValidationResult.setEntryName(entryName);
92  		constraintValidationResult.setAttributeName(attributeName);
93  		constraintValidationResult.setAttributePath(attributePath);
94  		
95  		String entryKey = getEntryValidationResultKey(entryName, attributePath);
96  		getEntryValidationResult(entryKey).getAttributeValidationResult(attributeName).addConstraintValidationResult(constraintValidationResult);
97  	}
98  
99      /**
100      * provides information used to display error messages to the user concerning a constraint validation
101      *
102      * @param attributeValueReader - provides access to the attribute being validated
103      * @param constraintName - a descriptive name of the current constraint processor
104      * @param errorKey - a key used to fetch an informational message to show the user
105      * @param errorParameters - parameters to substitute into the informational message
106      * @return a constraint validation result encompassing the information provided
107      */
108 	public ConstraintValidationResult addError(AttributeValueReader attributeValueReader, String constraintName, String errorKey, String... errorParameters) {
109 		ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
110 		constraintValidationResult.setError(errorKey, errorParameters);
111 		numberOfErrors++;
112 		return constraintValidationResult;
113 	}
114 
115     /**
116      * provides information used to display error messages to the user concerning a constraint validation
117      *
118      * @param constraintLabelKey - a key used to fetch an information message to show the user
119      * @param attributeValueReader - provides access to the attribute being validated
120      * @param constraintName - a descriptive name of the current constraint processor
121      * @param errorKey - a key used to fetch an error message to show the user
122      * @param errorParameters - parameters to substitute into the error message
123      * @return a constraint validation result encompassing the information provided
124      */
125     public ConstraintValidationResult addError(String constraintLabelKey, AttributeValueReader attributeValueReader, String constraintName,  String errorKey, String... errorParameters) {
126         ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
127         constraintValidationResult.setError(errorKey, errorParameters);
128         constraintValidationResult.setConstraintLabelKey(constraintLabelKey);
129         numberOfErrors++;
130         return constraintValidationResult;
131     }
132 
133     /**
134      provides information used to display warning messages to the user concerning a constraint validation
135      *
136      * @param attributeValueReader - provides access to the attribute being validated
137      * @param constraintName - a descriptive name of the current constraint processor
138      * @param errorKey - a key used to fetch a warning message to show the user
139      * @param errorParameters - parameters to substitute into the warning message
140      * @return a constraint validation result encompassing the information provided
141      */
142 	public ConstraintValidationResult addWarning(AttributeValueReader attributeValueReader, String constraintName, String errorKey, String... errorParameters) {
143 		if (errorLevel.getLevel() > ErrorLevel.WARN.getLevel())
144 			return new ConstraintValidationResult(constraintName, ErrorLevel.WARN);
145 		
146 		ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
147 		constraintValidationResult.setWarning(errorKey, errorParameters);
148 		numberOfWarnings++;
149 		return constraintValidationResult;
150 	}
151 
152     /**
153      * indicates that a constraint validation has succeeded
154      *
155      * @param attributeValueReader - provides access to the attribute being validated
156      * @param constraintName - a descriptive name of the current constraint processor
157      * @return a constraint validation result encompassing the information provided
158      */
159 	public ConstraintValidationResult addSuccess(AttributeValueReader attributeValueReader, String constraintName) {
160 		if (errorLevel.getLevel() > ErrorLevel.OK.getLevel())
161 			return new ConstraintValidationResult(constraintName, ErrorLevel.OK);
162 		
163 		return getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
164 	}
165 
166     /**
167      * indicates that a constraint validation has been skipped
168      *
169      * @param attributeValueReader - provides access to the attribute being validated
170      * @param constraintName - a descriptive name of the current constraint processor
171      * @return a constraint validation result encompassing the information provided
172      */
173 	public ConstraintValidationResult addSkipped(AttributeValueReader attributeValueReader, String constraintName) {
174 		if (errorLevel.getLevel() > ErrorLevel.OK.getLevel())
175 			return new ConstraintValidationResult(constraintName, ErrorLevel.INAPPLICABLE);
176 		
177 		ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
178 		constraintValidationResult.setStatus(ErrorLevel.INAPPLICABLE);
179 		return constraintValidationResult;
180 	}
181 
182     /**
183      * indicates that a constraint validation processing has been skipped
184      *
185      * @param attributeValueReader - provides access to the attribute being validated
186      * @param constraintName - a descriptive name of the current constraint processor
187      * @return a constraint validation result encompassing the information provided
188      */
189 	public ConstraintValidationResult addNoConstraint(AttributeValueReader attributeValueReader, String constraintName) {
190 		if (errorLevel.getLevel() > ErrorLevel.OK.getLevel())
191 			return new ConstraintValidationResult(constraintName, ErrorLevel.NOCONSTRAINT);
192 		
193 		ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
194 		constraintValidationResult.setStatus(ErrorLevel.NOCONSTRAINT);
195 		return constraintValidationResult;
196 	}
197 
198     /**
199      * gets an iterator over the various {@code ConstraintValidationResult}'s contained in this class
200      *
201      * @return an iterator
202      */
203 	public Iterator<ConstraintValidationResult> iterator() {
204 
205         iterator = new Iterator<ConstraintValidationResult>() {
206 
207             private Iterator<EntryValidationResult> entryIterator;
208             private Iterator<AttributeValidationResult> attributeIterator;
209             private Iterator<ConstraintValidationResult> constraintIterator;
210 
211             @Override
212             public boolean hasNext() {
213                 Iterator<ConstraintValidationResult> currentConstraintIterator = getCurrentConstraintIterator();
214                 return currentConstraintIterator != null && currentConstraintIterator.hasNext();
215             }
216 
217             @Override
218             public ConstraintValidationResult next() {
219                 Iterator<ConstraintValidationResult> currentConstraintIterator = getCurrentConstraintIterator();
220                 return currentConstraintIterator != null ? currentConstraintIterator.next() : null;
221             }
222 
223             @Override
224             public void remove() {
225                 throw new RuntimeException("Can't remove from this iterator!");
226             }
227 
228             private Iterator<ConstraintValidationResult> getCurrentConstraintIterator() {
229                 if (constraintIterator == null || constraintIterator.hasNext() == false) {
230                     Iterator<AttributeValidationResult> currentAttributeIterator = getCurrentAttributeIterator();
231                     if (currentAttributeIterator != null && currentAttributeIterator.hasNext()) {
232                         AttributeValidationResult currentAttributeValidationResult = currentAttributeIterator.next();
233                         constraintIterator = currentAttributeValidationResult.iterator();
234                     }
235                 }
236                 return constraintIterator;
237             }
238 
239             private Iterator<AttributeValidationResult> getCurrentAttributeIterator() {
240                 if (attributeIterator == null || attributeIterator.hasNext() == false) {
241                     Iterator<EntryValidationResult> currentEntryIterator = getCurrentEntryIterator();
242                     if (currentEntryIterator != null && currentEntryIterator.hasNext()) {
243                         EntryValidationResult currentEntryValidationResult = currentEntryIterator.next();
244                         attributeIterator = currentEntryValidationResult.iterator();
245                     }
246                 }
247                 return attributeIterator;
248             }
249 
250             private Iterator<EntryValidationResult> getCurrentEntryIterator() {
251                 if (entryIterator == null) // || entryIterator.hasNext() == false)
252                     entryIterator = entryValidationResultMap.values().iterator();
253                 return entryIterator;
254             }
255 
256         };
257 
258 		return iterator;
259 	}
260 
261     /**
262      * gets an entry validation result for the given {@code entryName}
263      *
264      * @param entryName - the name that the data dictionary uses to store metadata about the attribute
265      * @return the existing {@code EntryValidationResult} for the given {@code entryName} or creates a new one if absent
266      */
267 	protected EntryValidationResult getEntryValidationResult(String entryName) {
268 		EntryValidationResult entryValidationResult = entryValidationResultMap.get(entryName);
269 		if (entryValidationResult == null) {
270 			entryValidationResult = new EntryValidationResult(entryName);
271 			entryValidationResultMap.put(entryName, entryValidationResult);
272 		}
273 		return entryValidationResult;
274 	}
275 
276     /**
277      * composes a {@code ConstraintValidationResult} from the parameters given
278      *
279      * @param entryName - the name that the data dictionary uses to store metadata about the attribute
280      * @param attributeName - the attribute name
281      * @param attributePath - a string representation of specifically which attribute (at some depth) is being accessed
282      * @param constraintName - a descriptive name of the current constraint processor
283      * @return
284      */
285 	private ConstraintValidationResult getConstraintValidationResult(String entryName, String attributeName, String attributePath, String constraintName) {
286 	    String entryKey = getEntryValidationResultKey(entryName, attributePath);
287 	    ConstraintValidationResult constraintValidationResult = getEntryValidationResult(entryKey).getAttributeValidationResult(attributeName).getConstraintValidationResult(constraintName);
288 		constraintValidationResult.setEntryName(entryName);
289 		constraintValidationResult.setAttributeName(attributeName);
290 		constraintValidationResult.setAttributePath(attributePath);
291 		return constraintValidationResult;
292 	}
293 		
294 	/**
295      * gets the key to the {@link EntryValidationResult} entry in the EntryValidationResultMap
296      *
297      *  <p>Most cases entry key will be the entryName, unless the attribute is part of a collection,
298      * in which case entry key will be suffixed with index of attribute's parent item.</p>
299      * 
300      * @param entryName - the name that the data dictionary uses to store metadata about the attribute
301      * @param attributePath - a string representation of specifically which attribute (at some depth) is being accessed
302      * @return a key used to fetch an associated {@code EntryValidationResult}
303      */
304     private String getEntryValidationResultKey(String entryName, String attributePath) {
305         if (attributePath.contains("[")){
306             return entryName + "[" + ValidationUtils.getLastPathIndex(attributePath) + "]";
307         } 
308         return entryName;
309     }
310 
311     /**
312 	 * @return the errorLevel
313 	 */
314 	public ErrorLevel getErrorLevel() {
315 		return this.errorLevel;
316 	}
317 
318 	/**
319 	 * @param errorLevel the errorLevel to set
320 	 */
321 	public void setErrorLevel(ErrorLevel errorLevel) {
322 		this.errorLevel = errorLevel;
323 	}
324 
325 	/**
326 	 * @return the numberOfErrors
327 	 */
328 	public int getNumberOfErrors() {
329 		return this.numberOfErrors;
330 	}
331 
332 	/**
333 	 * @return the numberOfWarnings
334 	 */
335 	public int getNumberOfWarnings() {
336 		return this.numberOfWarnings;
337 	}
338 	
339 }