001    /**
002     * Copyright 2005-2012 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     * 
028     * @author Kuali Rice Team (rice.collab@kuali.org) 
029     */
030    public class DictionaryValidationResult implements Iterable<ConstraintValidationResult> {
031            
032            private Map<String, EntryValidationResult> entryValidationResultMap;
033            private ErrorLevel errorLevel;
034            
035            private int numberOfErrors;
036            private int numberOfWarnings;
037            
038            private Iterator<ConstraintValidationResult> iterator;
039            
040            public DictionaryValidationResult() {
041                    this.entryValidationResultMap = new LinkedHashMap<String, EntryValidationResult>();
042                    this.errorLevel = ErrorLevel.ERROR;
043                    this.numberOfErrors = 0;
044                    this.numberOfWarnings = 0;
045            }
046            
047            public void addConstraintValidationResult(AttributeValueReader attributeValueReader, ConstraintValidationResult constraintValidationResult) {
048                    
049                    // 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
050                    if (constraintValidationResult.getStatus().getLevel() < errorLevel.getLevel())
051                            return;
052                    
053                    switch (constraintValidationResult.getStatus()) {
054                    case ERROR:
055                            numberOfErrors++;
056                            break;
057                    case WARN:
058                            numberOfWarnings++;
059                            break;
060                    default:
061                            // Do nothing
062                    }
063                    
064                    // 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!
065                    String entryName = constraintValidationResult.getEntryName();
066                    String attributeName = constraintValidationResult.getAttributeName();
067                    String attributePath = constraintValidationResult.getAttributePath();
068                    
069                    if (entryName == null){
070                            entryName = attributeValueReader.getEntryName();
071                    }
072                    
073                    if (attributeName == null){
074                            attributeName = attributeValueReader.getAttributeName();
075                    }
076                    
077                    if (attributePath == null){
078                        attributePath = attributeValueReader.getPath();
079                    }
080                    
081                    constraintValidationResult.setEntryName(entryName);
082                    constraintValidationResult.setAttributeName(attributeName);
083                    constraintValidationResult.setAttributePath(attributePath);
084                    
085                    String entryKey = getEntryValdidationResultKey(entryName, attributePath);
086                    getEntryValidationResult(entryKey).getAttributeValidationResult(attributeName).addConstraintValidationResult(constraintValidationResult);
087            }
088            
089            public ConstraintValidationResult addError(AttributeValueReader attributeValueReader, String constraintName, String errorKey, String... errorParameters) {
090                    ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
091                    constraintValidationResult.setError(errorKey, errorParameters);
092                    numberOfErrors++;
093                    return constraintValidationResult;
094            }
095    
096        public ConstraintValidationResult addError(String constraintLabelKey, AttributeValueReader attributeValueReader, String constraintName,  String errorKey, String... errorParameters) {
097            ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
098            constraintValidationResult.setError(errorKey, errorParameters);
099            constraintValidationResult.setConstraintLabelKey(constraintLabelKey);
100            numberOfErrors++;
101            return constraintValidationResult;
102        }
103            
104            public ConstraintValidationResult addWarning(AttributeValueReader attributeValueReader, String constraintName, String errorKey, String... errorParameters) {
105                    if (errorLevel.getLevel() > ErrorLevel.WARN.getLevel())
106                            return new ConstraintValidationResult(constraintName, ErrorLevel.WARN);
107                    
108                    ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
109                    constraintValidationResult.setWarning(errorKey, errorParameters);
110                    numberOfWarnings++;
111                    return constraintValidationResult;
112            }
113    
114            public ConstraintValidationResult addSuccess(AttributeValueReader attributeValueReader, String constraintName) {
115                    if (errorLevel.getLevel() > ErrorLevel.OK.getLevel())
116                            return new ConstraintValidationResult(constraintName, ErrorLevel.OK);
117                    
118                    return getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
119            }
120            
121            public ConstraintValidationResult addSkipped(AttributeValueReader attributeValueReader, String constraintName) {
122                    if (errorLevel.getLevel() > ErrorLevel.OK.getLevel())
123                            return new ConstraintValidationResult(constraintName, ErrorLevel.INAPPLICABLE);
124                    
125                    ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
126                    constraintValidationResult.setStatus(ErrorLevel.INAPPLICABLE);
127                    return constraintValidationResult;
128            }
129            
130            public ConstraintValidationResult addNoConstraint(AttributeValueReader attributeValueReader, String constraintName) {
131                    if (errorLevel.getLevel() > ErrorLevel.OK.getLevel())
132                            return new ConstraintValidationResult(constraintName, ErrorLevel.NOCONSTRAINT);
133                    
134                    ConstraintValidationResult constraintValidationResult = getConstraintValidationResult(attributeValueReader.getEntryName(), attributeValueReader.getAttributeName(), attributeValueReader.getPath(), constraintName);
135                    constraintValidationResult.setStatus(ErrorLevel.NOCONSTRAINT);
136                    return constraintValidationResult;
137            }
138            
139            public Iterator<ConstraintValidationResult> iterator() {
140    
141            iterator = new Iterator<ConstraintValidationResult>() {
142    
143                private Iterator<EntryValidationResult> entryIterator;
144                private Iterator<AttributeValidationResult> attributeIterator;
145                private Iterator<ConstraintValidationResult> constraintIterator;
146    
147                @Override
148                public boolean hasNext() {
149                    Iterator<ConstraintValidationResult> currentConstraintIterator = getCurrentConstraintIterator();
150                    return currentConstraintIterator != null && currentConstraintIterator.hasNext();
151                }
152    
153                @Override
154                public ConstraintValidationResult next() {
155                    Iterator<ConstraintValidationResult> currentConstraintIterator = getCurrentConstraintIterator();
156                    return currentConstraintIterator != null ? currentConstraintIterator.next() : null;
157                }
158    
159                @Override
160                public void remove() {
161                    throw new RuntimeException("Can't remove from this iterator!");
162                }
163    
164                private Iterator<ConstraintValidationResult> getCurrentConstraintIterator() {
165                    if (constraintIterator == null || constraintIterator.hasNext() == false) {
166                        Iterator<AttributeValidationResult> currentAttributeIterator = getCurrentAttributeIterator();
167                        if (currentAttributeIterator != null && currentAttributeIterator.hasNext()) {
168                            AttributeValidationResult currentAttributeValidationResult = currentAttributeIterator.next();
169                            constraintIterator = currentAttributeValidationResult.iterator();
170                        }
171                    }
172                    return constraintIterator;
173                }
174    
175                private Iterator<AttributeValidationResult> getCurrentAttributeIterator() {
176                    if (attributeIterator == null || attributeIterator.hasNext() == false) {
177                        Iterator<EntryValidationResult> currentEntryIterator = getCurrentEntryIterator();
178                        if (currentEntryIterator != null && currentEntryIterator.hasNext()) {
179                            EntryValidationResult currentEntryValidationResult = currentEntryIterator.next();
180                            attributeIterator = currentEntryValidationResult.iterator();
181                        }
182                    }
183                    return attributeIterator;
184                }
185    
186                private Iterator<EntryValidationResult> getCurrentEntryIterator() {
187                    if (entryIterator == null) // || entryIterator.hasNext() == false)
188                        entryIterator = entryValidationResultMap.values().iterator();
189                    return entryIterator;
190                }
191    
192            };
193    
194                    return iterator;
195            }
196            
197            protected EntryValidationResult getEntryValidationResult(String entryName) {
198                    EntryValidationResult entryValidationResult = entryValidationResultMap.get(entryName);
199                    if (entryValidationResult == null) {
200                            entryValidationResult = new EntryValidationResult(entryName);
201                            entryValidationResultMap.put(entryName, entryValidationResult);
202                    }
203                    return entryValidationResult;
204            }
205            
206            private ConstraintValidationResult getConstraintValidationResult(String entryName, String attributeName, String attributePath, String constraintName) {
207                String entryKey = getEntryValdidationResultKey(entryName, attributePath);
208                ConstraintValidationResult constraintValidationResult = getEntryValidationResult(entryKey).getAttributeValidationResult(attributeName).getConstraintValidationResult(constraintName);
209                    constraintValidationResult.setEntryName(entryName);
210                    constraintValidationResult.setAttributeName(attributeName);
211                    constraintValidationResult.setAttributePath(attributePath);
212                    return constraintValidationResult;
213            }
214                    
215            /**
216         * Returns the key to the EntryValidationResult entry in the EntryValidationResultMap.
217         * Most cases entry key will be the entryName, unless the attribute is part of a collection,
218         * in which case entry key will be suffixed with index of attribute's parent item.
219         * 
220         * @param entryName
221         * @param attributePath
222         * @return
223         */
224        private String getEntryValdidationResultKey(String entryName, String attributePath) {
225            if (attributePath.contains("[")){
226                return entryName + "[" + ValidationUtils.getLastPathIndex(attributePath) + "]";
227            } 
228            return entryName;
229        }
230    
231        /**
232             * @return the errorLevel
233             */
234            public ErrorLevel getErrorLevel() {
235                    return this.errorLevel;
236            }
237    
238            /**
239             * @param errorLevel the errorLevel to set
240             */
241            public void setErrorLevel(ErrorLevel errorLevel) {
242                    this.errorLevel = errorLevel;
243            }
244    
245            /**
246             * @return the numberOfErrors
247             */
248            public int getNumberOfErrors() {
249                    return this.numberOfErrors;
250            }
251    
252            /**
253             * @return the numberOfWarnings
254             */
255            public int getNumberOfWarnings() {
256                    return this.numberOfWarnings;
257            }
258            
259    }