View Javadoc
1   /**
2    * Copyright 2005-2014 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,
58              ConstraintValidationResult constraintValidationResult) {
59  
60          // 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
61          if (constraintValidationResult.getStatus().getLevel() < errorLevel.getLevel()) {
62              return;
63          }
64  
65          switch (constraintValidationResult.getStatus()) {
66              case ERROR:
67                  numberOfErrors++;
68                  break;
69              case WARN:
70                  numberOfWarnings++;
71                  break;
72              default:
73                  // Do nothing
74          }
75  
76          // 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!
77          String entryName = constraintValidationResult.getEntryName();
78          String attributeName = constraintValidationResult.getAttributeName();
79          String attributePath = constraintValidationResult.getAttributePath();
80  
81          if (entryName == null) {
82              entryName = attributeValueReader.getEntryName();
83          }
84  
85          if (attributeName == null) {
86              attributeName = attributeValueReader.getAttributeName();
87          }
88  
89          if (attributePath == null) {
90              attributePath = attributeValueReader.getPath();
91          }
92  
93          constraintValidationResult.setEntryName(entryName);
94          constraintValidationResult.setAttributeName(attributeName);
95          constraintValidationResult.setAttributePath(attributePath);
96  
97          String entryKey = getEntryValidationResultKey(entryName, attributePath);
98          getEntryValidationResult(entryKey).getAttributeValidationResult(attributeName).addConstraintValidationResult(
99                  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 }