View Javadoc

1   /**
2    * Copyright 2005-2013 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.util;
17  
18  
19  import org.apache.commons.lang.StringEscapeUtils;
20  import org.apache.commons.lang.StringUtils;
21  import org.apache.commons.lang.builder.EqualsBuilder;
22  import org.apache.commons.lang.builder.HashCodeBuilder;
23  import org.apache.commons.lang.builder.ToStringBuilder;
24  import org.springframework.util.AutoPopulatingList;
25  
26  import java.io.Serializable;
27  import java.util.ArrayList;
28  import java.util.Iterator;
29  import java.util.LinkedHashMap;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  
34  
35  /**
36   * Holds errors due to validation. Keys of map represent property paths, and value is a AutoPopulatingList that contains resource string
37   * keys (to retrieve the error message).
38   *
39   * Note, prior to rice 0.9.4, this class implemented {@link java.util.Map}.  The implements has been removed as of rice 0.9.4
40   */
41  public class MessageMap implements Serializable {
42  	
43      private static final long serialVersionUID = -2328635367656516150L;
44      
45      private List<String> errorPath = new ArrayList<String>();
46      private Map<String, AutoPopulatingList<ErrorMessage>> errorMessages = new LinkedHashMap<String, AutoPopulatingList<ErrorMessage>>();
47      private Map<String, AutoPopulatingList<ErrorMessage>> warningMessages = new LinkedHashMap<String, AutoPopulatingList<ErrorMessage>>();
48      private Map<String, AutoPopulatingList<ErrorMessage>> infoMessages = new LinkedHashMap<String, AutoPopulatingList<ErrorMessage>>();
49  
50      public MessageMap() {}
51  
52      public MessageMap(MessageMap messageMap) {
53      	this.errorPath = messageMap.errorPath;
54      	this.errorMessages = messageMap.errorMessages;
55      	this.warningMessages = messageMap.warningMessages;
56      	this.infoMessages = messageMap.infoMessages;
57      }
58  
59  
60      public void merge(MessageMap messageMap){
61      	if(messageMap != null){
62      		if(messageMap.hasErrors()){
63      			merge(messageMap.getErrorMessages(), errorMessages);
64      		}
65      		if(messageMap.hasInfo()){
66      			merge(messageMap.getInfoMessages(), infoMessages);
67      		}
68      		if(messageMap.hasWarnings()){
69      			merge(messageMap.getWarningMessages(), warningMessages);
70      		}
71  
72      	}
73  
74      }
75  
76      /**
77       *
78       * This method takes one message map and merges it into another.  Makes sure there are no duplicates.
79       *
80       * @param messagesFrom
81       * @param messagesTo
82       */
83      protected void merge(Map<String, AutoPopulatingList<ErrorMessage>> messagesFrom, Map<String, AutoPopulatingList<ErrorMessage>> messagesTo){
84      	for(String key : messagesFrom.keySet()){
85  
86      		if(messagesTo.containsKey(key)){
87      			// now we need to merge the messages
88      			AutoPopulatingList<ErrorMessage> tal = messagesFrom.get(key);
89      			AutoPopulatingList<ErrorMessage> parentList = messagesTo.get(key);
90  
91      			for(Object o :tal){
92  
93      				 if ( !parentList.contains( o ) ) {
94      					 parentList.add((ErrorMessage)o);
95      			     }
96      			}
97  
98      		}else{
99      			messagesTo.put(key, messagesFrom.get(key));
100     		}
101 
102     	}
103 
104     }
105     /**
106      * Adds an error to the map under the given propertyName and adds an array of message parameters. This will fully prepend the
107      * propertyName with the current errorPath.
108      *
109      * @param propertyName name of the property to add error under
110      * @param errorKey resource key used to retrieve the error text from the error message resource bundle
111      * @param errorParameters zero or more string parameters for the displayed error message
112      * @return AutoPopulatingList
113      */
114     public AutoPopulatingList<ErrorMessage> putError(String propertyName, String errorKey, String... errorParameters) {
115         return putMessageInMap(errorMessages, propertyName, errorKey, true, true, errorParameters);
116     }
117 
118     public AutoPopulatingList<ErrorMessage> putWarning(String propertyName, String messageKey, String... messageParameters) {
119         return putMessageInMap(warningMessages, propertyName, messageKey, true, true, messageParameters);
120     }
121 
122     public AutoPopulatingList<ErrorMessage> putInfo(String propertyName, String messageKey, String... messageParameters) {
123         return putMessageInMap(infoMessages, propertyName, messageKey, true, true, messageParameters);
124     }
125 
126     /**
127      * Adds an error to the map under the given propertyName and adds an array of message parameters. This will
128      * <strong>not</strong> prepend the propertyName with the current errorPath.
129      *
130      * @param propertyName name of the property to add error under
131      * @param errorKey resource key used to retrieve the error text from the error message resource bundle
132      * @param errorParameters zero or more string parameters for the displayed error message
133      * @return AutoPopulatingList
134      */
135     public AutoPopulatingList<ErrorMessage> putErrorWithoutFullErrorPath(String propertyName, String errorKey, String... errorParameters) {
136         return putMessageInMap(errorMessages, propertyName, errorKey, false, true, errorParameters);
137     }
138 
139     public AutoPopulatingList<ErrorMessage> putWarningWithoutFullErrorPath(String propertyName, String messageKey, String... messageParameters) {
140         return putMessageInMap(warningMessages, propertyName, messageKey, false, true, messageParameters);
141     }
142 
143     public AutoPopulatingList<ErrorMessage> putInfoWithoutFullErrorPath(String propertyName, String messageKey, String... messageParameters) {
144         return putMessageInMap(infoMessages, propertyName, messageKey, false, true, messageParameters);
145     }
146 
147     /**
148      * Adds an error related to a particular section identified by its section ID.  For maintenance documents, the section ID is identified
149      * by calling {@link org.kuali.rice.kns.datadictionary.MaintainableSectionDefinition#getId()}
150      *
151      * @param sectionId
152      * @param errorKey
153      * @param errorParameters
154      * @return
155      */
156     public AutoPopulatingList<ErrorMessage> putErrorForSectionId(String sectionId, String errorKey, String... errorParameters) {
157     	return putErrorWithoutFullErrorPath(sectionId, errorKey, errorParameters);
158     }
159 
160     public AutoPopulatingList<ErrorMessage> putWarningForSectionId(String sectionId, String messageKey, String... messageParameters) {
161     	return putWarningWithoutFullErrorPath(sectionId, messageKey, messageParameters);
162     }
163 
164     public AutoPopulatingList<ErrorMessage> putInfoForSectionId(String sectionId, String messageKey, String... messageParameters) {
165     	return putInfoWithoutFullErrorPath(sectionId, messageKey, messageParameters);
166     }
167 
168     /**
169      * adds an error to the map under the given propertyName and adds an array of message parameters.
170      *
171      * @param propertyName name of the property to add error under
172      * @param messageKey resource key used to retrieve the error text from the error message resource bundle
173      * @param prependFullErrorPath true if you want the whole parent error path prepended, false otherwise
174      * @param escapeHtmlMessageParameters whether to escape HTML characters in the message parameters, provides protection against XSS attacks
175      * @param messageParameters zero or more string parameters for the displayed error message
176      * @return TypeArrayList
177      */
178     private AutoPopulatingList<ErrorMessage> putMessageInMap(Map<String, AutoPopulatingList<ErrorMessage>> messagesMap, String propertyName, String messageKey, boolean prependFullErrorPath, boolean escapeHtmlMessageParameters, String... messageParameters) {
179         if (StringUtils.isBlank(propertyName)) {
180             throw new IllegalArgumentException("invalid (blank) propertyName");
181         }
182         if (StringUtils.isBlank(messageKey)) {
183             throw new IllegalArgumentException("invalid (blank) errorKey");
184         }
185 
186         // check if we have previous errors for this property
187         AutoPopulatingList<ErrorMessage> errorList = null;
188         String propertyKey = getKeyPath(propertyName, prependFullErrorPath);
189         if (messagesMap.containsKey(propertyKey)) {
190             errorList = messagesMap.get(propertyKey);
191         }
192         else {
193             errorList = new AutoPopulatingList<ErrorMessage>(ErrorMessage.class);
194         }
195 
196         if (escapeHtmlMessageParameters && messageParameters != null) {
197         	String[] filteredMessageParameters = new String[messageParameters.length];
198         	for (int i = 0; i < messageParameters.length; i++) {
199         		filteredMessageParameters[i] = StringEscapeUtils.escapeHtml(messageParameters[i]);
200         	}
201         	messageParameters = filteredMessageParameters;
202         }
203 
204         // add error to list
205         ErrorMessage errorMessage = new ErrorMessage(messageKey, messageParameters);
206         // check if this error has already been added to the list
207         if ( !errorList.contains( errorMessage ) ) {
208             errorList.add(errorMessage);
209         }
210 
211         return messagesMap.put(propertyKey, errorList);
212     }
213 
214     /**
215      * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages will be
216      * replaced with a new ErrorMessage with the given replaceKey and replaceParameters.
217      *
218      * @param propertyName name of the property where existing error will be replaced
219      * @param targetKey error key of message to be replaced
220      * @paran replaceKey error key which will replace targetKey
221      * @param replaceParameters zero or more string parameters for the replacement error message
222      * @return true if the replacement occurred
223      */
224     public boolean replaceError(String propertyName, String targetKey, String replaceKey, String... replaceParameters) {
225         return replaceError(propertyName, targetKey, true, replaceKey, replaceParameters);
226     }
227 
228     /**
229      * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages will be
230      * replaced with a new ErrorMessage with the given replaceKey and replaceParameters. The targetKey and replaceKey will be
231      * prepended with the current errorPath, if any.
232      *
233      *
234      * @param propertyName name of the property where existing error will be replaced
235      * @param targetKey error key of message to be replaced
236      * @paran replaceKey error key which will replace targetKey
237      * @param replaceParameters zero or more string parameters for the replacement error message
238      * @return true if the replacement occurred
239      */
240     public boolean replaceErrorWithoutFullErrorPath(String propertyName, String targetKey, String replaceKey, String... replaceParameters) {
241         return replaceError(propertyName, targetKey, false, replaceKey, replaceParameters);
242     }
243 
244 
245     /**
246      * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages will be
247      * replaced with a new ErrorMessage with the given replaceKey and replaceParameters.
248      *
249      * @param propertyName name of the property to add error under
250      * @param targetKey resource key used to retrieve the error text
251      * @param withFullErrorPath true if you want the whole parent error path appended, false otherwise
252      * @param replaceParameters zero or more string parameters for the displayed error message
253      * @return true if the replacement occurred
254      */
255     private boolean replaceError(String propertyName, String targetKey, boolean withFullErrorPath, String replaceKey, String... replaceParameters) {
256         boolean replaced = false;
257 
258         if (StringUtils.isBlank(propertyName)) {
259             throw new IllegalArgumentException("invalid (blank) propertyName");
260         }
261         if (StringUtils.isBlank(targetKey)) {
262             throw new IllegalArgumentException("invalid (blank) targetKey");
263         }
264         if (StringUtils.isBlank(replaceKey)) {
265             throw new IllegalArgumentException("invalid (blank) replaceKey");
266         }
267 
268         // check if we have previous errors for this property
269         AutoPopulatingList<ErrorMessage> errorList = null;
270         String propertyKey = getKeyPath(propertyName, withFullErrorPath);
271         if (errorMessages.containsKey(propertyKey)) {
272             errorList = errorMessages.get(propertyKey);
273 
274             // look for the specific targetKey
275             for (int i = 0; i < errorList.size(); ++i) {
276                 ErrorMessage em = errorList.get(i);
277 
278                 // replace matching messages
279                 if (em.getErrorKey().equals(targetKey)) {
280                     ErrorMessage rm = new ErrorMessage(replaceKey, replaceParameters);
281                     errorList.set(i, rm);
282                     replaced = true;
283                 }
284             }
285         }
286 
287         return replaced;
288     }
289 
290 
291     /**
292      * Returns true if the named field has a message with the given errorKey
293      *
294      * @param errorKey
295      * @param fieldName
296      * @return boolean
297      */
298     public boolean fieldHasMessage(String fieldName, String errorKey) {
299         boolean found = false;
300 
301         List<ErrorMessage> fieldMessages = errorMessages.get(fieldName);
302         if (fieldMessages != null) {
303             for (Iterator<ErrorMessage> i = fieldMessages.iterator(); !found && i.hasNext();) {
304                 ErrorMessage errorMessage = i.next();
305                 found = errorMessage.getErrorKey().equals(errorKey);
306             }
307         }
308 
309         return found;
310     }
311 
312     /**
313      * Returns the number of messages for the given field
314      *
315      * @param fieldName
316      * @return int
317      */
318     public int countFieldMessages(String fieldName) {
319         int count = 0;
320 
321         List<ErrorMessage> fieldMessages = errorMessages.get(fieldName);
322         if (fieldMessages != null) {
323             count = fieldMessages.size();
324         }
325 
326         return count;
327     }
328 
329 
330     /**
331      * @return true if the given messageKey is associated with some property in this ErrorMap
332      */
333     public boolean containsMessageKey(String messageKey) {
334         ErrorMessage foundMessage = null;
335 
336         if (!hasNoErrors()) {
337             for (Iterator<Map.Entry<String, AutoPopulatingList<ErrorMessage>>> i = getAllPropertiesAndErrors().iterator(); (foundMessage == null) && i.hasNext();) {
338             	Map.Entry<String, AutoPopulatingList<ErrorMessage>> e = i.next();
339                 AutoPopulatingList<ErrorMessage> entryErrorList = e.getValue();
340                 for (Iterator<ErrorMessage> j = entryErrorList.iterator(); j.hasNext();) {
341                     ErrorMessage em = j.next();
342                     if (messageKey.equals(em.getErrorKey())) {
343                         foundMessage = em;
344                     }
345                 }
346             }
347         }
348 
349         return (foundMessage != null);
350     }
351 
352 
353     private int getMessageCount(Map<String, AutoPopulatingList<ErrorMessage>> messageMap) {
354         int messageCount = 0;
355         for (Iterator<String> iter = messageMap.keySet().iterator(); iter.hasNext();) {
356             String errorKey = iter.next();
357             List<ErrorMessage> errors = messageMap.get(errorKey);
358             messageCount += errors.size();
359         }
360 
361         return messageCount;
362     }
363 
364     /**
365      * Counts the total number of error messages in the map
366      *
367      * @return returns an int for the total number of errors
368      */
369     public int getErrorCount() {
370     	return getMessageCount(errorMessages);
371     }
372 
373     /**
374      * Counts the total number of warning messages in the map
375      *
376      * @return returns an int for the total number of warnings
377      */
378     public int getWarningCount() {
379     	return getMessageCount(warningMessages);
380     }
381 
382     /**
383      * Counts the total number of info messages in the map
384      *
385      * @return returns an int for the total number of info
386      */
387     public int getInfoCount() {
388     	return getMessageCount(infoMessages);
389     }
390 
391     /**
392      * @param path
393      * @return Returns a List of ErrorMessages for the given path
394      */
395     public AutoPopulatingList<ErrorMessage> getMessages(String path) {
396         return errorMessages.get(path);
397     }
398 
399     /**
400      * Adds a string prefix to the error path.
401      *
402      * @param parentName
403      */
404     public void addToErrorPath(String parentName) {
405         errorPath.add(parentName);
406     }
407 
408     /**
409      * This method returns the list that holds the error path values.
410      *
411      * @return List
412      */
413     public List<String> getErrorPath() {
414         return errorPath;
415     }
416 
417     /**
418      * Removes a string prefix from the error path.
419      *
420      * @param parentName
421      * @return boolean Returns true if the parentName existed, false otherwise.
422      */
423     public boolean removeFromErrorPath(String parentName) {
424         return errorPath.remove(parentName);
425     }
426 
427     /**
428      * Clears the errorPath.
429      */
430     public void clearErrorPath() {
431         errorPath.clear();
432     }
433 
434     /**
435      * This is what's prepended to the beginning of the key. This is built by iterating over all of the entries in the errorPath
436      * list and concatenating them together with a "."
437      *
438      * @return String Returns the keyPath.
439      * @param propertyName
440      * @param prependFullErrorPath
441      */
442     public String getKeyPath(String propertyName, boolean prependFullErrorPath) {
443         String keyPath = "";
444 
445         if (KRADConstants.GLOBAL_ERRORS.equals(propertyName)) {
446             return KRADConstants.GLOBAL_ERRORS;
447         }
448 
449         if (!errorPath.isEmpty() && prependFullErrorPath) {
450             keyPath = StringUtils.join(errorPath.iterator(), ".");
451             keyPath += (keyPath!=null && keyPath.endsWith("."))?propertyName:"." + propertyName;
452         }
453         else {
454             keyPath = propertyName;
455         }
456 
457         return keyPath;
458     }
459 
460     /**
461      * @return List of the property names that have errors.
462      */
463     public List<String> getPropertiesWithErrors() {
464         List<String> properties = new ArrayList<String>();
465 
466         for (Iterator<String> iter = errorMessages.keySet().iterator(); iter.hasNext();) {
467             properties.add(iter.next());
468         }
469 
470         return properties;
471     }
472 
473     /**
474      * @return List of the property names that have warnings.
475      */
476     public List<String> getPropertiesWithWarnings() {
477         List<String> properties = new ArrayList<String>(warningMessages.keySet());
478         return properties;
479     }
480 
481     /**
482      * @return List of the property names that have info.
483      */
484     public List<String> getPropertiesWithInfo() {
485         List<String> properties = new ArrayList<String>(infoMessages.keySet());
486         return properties;
487     }
488 
489     public void clearErrorMessages() {
490     	errorMessages.clear();
491     }
492 
493     public boolean doesPropertyHaveError(String key) {
494     	return errorMessages.containsKey(key);
495     }
496 
497     /**
498      * @param pattern comma separated list of keys, optionally ending with * wildcard
499      */
500     public boolean containsKeyMatchingPattern(String pattern) {
501         List<String> simplePatterns = new ArrayList<String>();
502         List<String> wildcardPatterns = new ArrayList<String>();
503         String[] patterns = pattern.split(",");
504         for (int i = 0; i < patterns.length; i++) {
505             String s = patterns[i];
506             if (s.endsWith("*")) {
507                 wildcardPatterns.add(s.substring(0, s.length() - 1));
508             }
509             else {
510                 simplePatterns.add(s);
511             }
512         }
513         for (Iterator<String> keys = errorMessages.keySet().iterator(); keys.hasNext();) {
514             String key = keys.next();
515             if (simplePatterns.contains(key)) {
516                 return true;
517             }
518             for (Iterator<String> wildcardIterator = wildcardPatterns.iterator(); wildcardIterator.hasNext();) {
519                 String wildcard = wildcardIterator.next();
520                 if (key.startsWith(wildcard)) {
521                     return true;
522                 }
523             }
524         }
525         return false;
526     }
527 
528     public Set<Map.Entry<String, AutoPopulatingList<ErrorMessage>>> getAllPropertiesAndErrors() {
529     	return errorMessages.entrySet();
530     }
531 
532     public AutoPopulatingList<ErrorMessage> getErrorMessagesForProperty(String propertyName) {
533     	return errorMessages.get(propertyName);
534     }
535 
536     public AutoPopulatingList<ErrorMessage> getWarningMessagesForProperty(String propertyName) {
537     	return warningMessages.get(propertyName);
538     }
539 
540     public AutoPopulatingList<ErrorMessage> getInfoMessagesForProperty(String propertyName) {
541     	return infoMessages.get(propertyName);
542     }
543     
544 	/**
545 	 * Gets a list of lists that represent errors that matched by the
546 	 * propertyName passed in (multiple lists because the wildcard can match
547 	 * multiple keys). If wildcard is true, the propertyName ends with a
548 	 * wildcard character. Otherwise, it will only match on the single key and
549 	 * return a list with one list
550 	 * 
551 	 * @param propertyName
552 	 * @param allowWildcard
553 	 * @return
554 	 */
555 	public List<AutoPopulatingList<ErrorMessage>> getErrorMessagesForProperty(
556 			String propertyName, boolean allowWildcard) {
557 		List<AutoPopulatingList<ErrorMessage>> foundMessages = new ArrayList<AutoPopulatingList<ErrorMessage>>();
558 		if (allowWildcard) {
559 			boolean wildcard = false;
560 			if (propertyName.endsWith("*")) {
561 				wildcard = true;
562 				propertyName = propertyName.substring(0,
563 						propertyName.length() - 1);
564 			}
565 			for (Iterator<String> keys = errorMessages.keySet().iterator(); keys
566 					.hasNext();) {
567 				String key = keys.next();
568 				if (!wildcard && propertyName.equals(key)) {
569 					foundMessages.add(errorMessages.get(key));
570 					break;
571 				} else if (wildcard && key.startsWith(propertyName)) {
572 					foundMessages.add(errorMessages.get(key));
573 				}
574 			}
575 		} else {
576 			foundMessages.add(getErrorMessagesForProperty(propertyName));
577 		}
578 
579 		return foundMessages;
580 	}
581 
582 	/**
583 	 * Gets a list of lists that represent warnings that matched by the
584 	 * propertyName passed in (multiple lists because the wildcard can match
585 	 * multiple keys). If wildcard is true, the propertyName ends with a
586 	 * wildcard character. Otherwise, it will only match on the single key and
587 	 * return a list with one list.
588 	 * 
589 	 * @param propertyName
590 	 * @param allowWildcard
591 	 * @return
592 	 */
593 	public List<AutoPopulatingList<ErrorMessage>> getWarningMessagesForProperty(
594 			String propertyName, boolean allowWildcard) {
595 		List<AutoPopulatingList<ErrorMessage>> foundMessages = new ArrayList<AutoPopulatingList<ErrorMessage>>();
596 		if (allowWildcard) {
597 			boolean wildcard = false;
598 			if (propertyName.endsWith("*")) {
599 				wildcard = true;
600 				propertyName = propertyName.substring(0,
601 						propertyName.length() - 1);
602 			}
603 			for (Iterator<String> keys = warningMessages.keySet().iterator(); keys
604 					.hasNext();) {
605 				String key = keys.next();
606 				if (!wildcard && propertyName.equals(key)) {
607 					foundMessages.add(warningMessages.get(key));
608 					break;
609 				} else if (wildcard && key.startsWith(propertyName)) {
610 					foundMessages.add(warningMessages.get(key));
611 				}
612 			}
613 		} else {
614 			foundMessages.add(getWarningMessagesForProperty(propertyName));
615 		}
616 
617 		return foundMessages;
618 	}
619 
620 	/**
621 	 * Gets a list of lists that represent info messages that matched by the
622 	 * propertyName passed in (multiple lists because the wildcard can match
623 	 * multiple keys). If wildcard is true, the propertyName ends with a
624 	 * wildcard character. If it is false, it will only match on the single key
625 	 * and return a list with one list.
626 	 * 
627 	 * @param propertyName
628 	 * @param allowWildcard
629 	 * @return
630 	 */
631 	public List<AutoPopulatingList<ErrorMessage>> getInfoMessagesForProperty(
632 			String propertyName, boolean allowWildcard) {
633 		List<AutoPopulatingList<ErrorMessage>> foundMessages = new ArrayList<AutoPopulatingList<ErrorMessage>>();
634 		if (allowWildcard) {
635 			boolean wildcard = false;
636 			if (propertyName.endsWith("*")) {
637 				wildcard = true;
638 				propertyName = propertyName.substring(0,
639 						propertyName.length() - 1);
640 			}
641 			for (Iterator<String> keys = infoMessages.keySet().iterator(); keys
642 					.hasNext();) {
643 				String key = keys.next();
644 				if (!wildcard && propertyName.equals(key)) {
645 					foundMessages.add(infoMessages.get(key));
646 					break;
647 				} else if (wildcard && key.startsWith(propertyName)) {
648 					foundMessages.add(infoMessages.get(key));
649 				}
650 			}
651 		} else {
652 			foundMessages.add(getInfoMessagesForProperty(propertyName));
653 		}
654 
655 		return foundMessages;
656 	}
657 
658     public boolean hasErrors() {
659     	return !errorMessages.isEmpty();
660     }
661 
662     public boolean hasNoErrors() {
663     	return errorMessages.isEmpty();
664     }
665 
666     public boolean hasWarnings() {
667     	return !warningMessages.isEmpty();
668     }
669 
670     public boolean hasNoWarnings() {
671     	return warningMessages.isEmpty();
672     }
673 
674     public boolean hasInfo() {
675     	return !infoMessages.isEmpty();
676     }
677 
678     public boolean hasNoInfo() {
679     	return infoMessages.isEmpty();
680     }
681 
682     public boolean hasMessages() {
683         if (!errorMessages.isEmpty()
684                 || !warningMessages.isEmpty()
685                 || !infoMessages.isEmpty()) {
686             return true;
687         }
688         return false;
689     }
690 
691     public boolean hasNoMessages() {
692         if (errorMessages.isEmpty()
693                 && warningMessages.isEmpty()
694                 && infoMessages.isEmpty()) {
695             return true;
696         }
697         return false;
698     }
699 
700     public Set<String> getAllPropertiesWithErrors() {
701     	return errorMessages.keySet();
702     }
703 
704     public Set<String> getAllPropertiesWithWarnings() {
705     	return warningMessages.keySet();
706     }
707 
708     public Set<String> getAllPropertiesWithInfo() {
709     	return infoMessages.keySet();
710     }
711 
712     public AutoPopulatingList<ErrorMessage> removeAllErrorMessagesForProperty(String property) {
713     	return errorMessages.remove(property);
714     }
715 
716     public AutoPopulatingList<ErrorMessage> removeAllWarningMessagesForProperty(String property) {
717     	return warningMessages.remove(property);
718     }
719 
720     public AutoPopulatingList<ErrorMessage> removeAllInfoMessagesForProperty(String property) {
721     	return infoMessages.remove(property);
722     }
723 
724     public int getNumberOfPropertiesWithErrors() {
725     	return errorMessages.size();
726     }
727 
728     public Map<String, AutoPopulatingList<ErrorMessage>> getErrorMessages() {
729         return this.errorMessages;
730     }
731 
732     public Map<String, AutoPopulatingList<ErrorMessage>> getWarningMessages() {
733         return this.warningMessages;
734     }
735 
736     public Map<String, AutoPopulatingList<ErrorMessage>> getInfoMessages() {
737         return this.infoMessages;
738     }
739 
740     @Override
741     public boolean equals(Object o) {
742         return EqualsBuilder.reflectionEquals(this, o);
743     }
744 
745     @Override
746     public int hashCode() {
747         return HashCodeBuilder.reflectionHashCode(this);
748     }
749 
750     @Override
751     public String toString() {
752         return ToStringBuilder.reflectionToString(this);
753     }
754 }