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