001/** 002 * Copyright 2005-2016 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 */ 016package org.kuali.rice.krad.util; 017 018import org.apache.commons.lang.StringEscapeUtils; 019import org.apache.commons.lang.StringUtils; 020import org.apache.commons.lang.builder.EqualsBuilder; 021import org.apache.commons.lang.builder.HashCodeBuilder; 022import org.apache.commons.lang.builder.ToStringBuilder; 023import org.springframework.util.AutoPopulatingList; 024 025import java.io.Serializable; 026import java.util.ArrayList; 027import java.util.Iterator; 028import java.util.LinkedHashMap; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032 033/** 034 * Holds errors due to validation 035 * 036 * <p>Keys of map represent property paths, and value is a AutoPopulatingList that contains resource string 037 * keys (to retrieve the error message).</p> 038 * 039 * <p>Note, prior to rice 0.9.4, this class implemented {@link java.util.Map}. The implements has been removed as of 040 * rice 0.9.4</p> 041 * 042 * @author Kuali Rice Team (rice.collab@kuali.org) 043 */ 044public class MessageMap implements Serializable { 045 private static final long serialVersionUID = -2328635367656516150L; 046 047 private List<String> errorPath = new ArrayList<String>(); 048 049 private Map<String, AutoPopulatingList<ErrorMessage>> errorMessages = 050 new LinkedHashMap<String, AutoPopulatingList<ErrorMessage>>(); 051 private Map<String, AutoPopulatingList<ErrorMessage>> warningMessages = 052 new LinkedHashMap<String, AutoPopulatingList<ErrorMessage>>(); 053 private Map<String, AutoPopulatingList<ErrorMessage>> infoMessages = 054 new LinkedHashMap<String, AutoPopulatingList<ErrorMessage>>(); 055 private AutoPopulatingList<GrowlMessage> growlMessages; 056 057 public MessageMap() { 058 growlMessages = new AutoPopulatingList<GrowlMessage>(GrowlMessage.class); 059 } 060 061 public MessageMap(MessageMap messageMap) { 062 this.errorPath = messageMap.errorPath; 063 this.errorMessages = messageMap.errorMessages; 064 this.warningMessages = messageMap.warningMessages; 065 this.infoMessages = messageMap.infoMessages; 066 067 growlMessages = new AutoPopulatingList<GrowlMessage>(GrowlMessage.class); 068 } 069 070 public void merge(MessageMap messageMap) { 071 if (messageMap != null) { 072 if (messageMap.hasErrors()) { 073 merge(messageMap.getErrorMessages(), errorMessages); 074 } 075 if (messageMap.hasInfo()) { 076 merge(messageMap.getInfoMessages(), infoMessages); 077 } 078 if (messageMap.hasWarnings()) { 079 merge(messageMap.getWarningMessages(), warningMessages); 080 } 081 if (messageMap.getGrowlMessages() != null) { 082 growlMessages.addAll(messageMap.getGrowlMessages()); 083 } 084 } 085 086 } 087 088 /** 089 * Takes one message map and merges it into another. Makes sure there are no duplicates. 090 * 091 * @param messagesFrom 092 * @param messagesTo 093 */ 094 public void merge(Map<String, AutoPopulatingList<ErrorMessage>> messagesFrom, 095 Map<String, AutoPopulatingList<ErrorMessage>> messagesTo) { 096 for (String key : messagesFrom.keySet()) { 097 098 if (messagesTo.containsKey(key)) { 099 // now we need to merge the messages 100 AutoPopulatingList<ErrorMessage> tal = messagesFrom.get(key); 101 AutoPopulatingList<ErrorMessage> parentList = messagesTo.get(key); 102 103 for (Object o : tal) { 104 105 if (!parentList.contains(o)) { 106 parentList.add((ErrorMessage) o); 107 } 108 } 109 110 } else { 111 messagesTo.put(key, messagesFrom.get(key)); 112 } 113 114 } 115 } 116 117 public AutoPopulatingList<ErrorMessage> putError(String propertyName, String errorKey, String... errorParameters) { 118 ErrorMessage message = new ErrorMessage(errorKey, errorParameters); 119 return putMessageInMap(errorMessages, propertyName, message, true, true); 120 } 121 122 public AutoPopulatingList<ErrorMessage> putWarning(String propertyName, String messageKey, 123 String... messageParameters) { 124 ErrorMessage message = new ErrorMessage(messageKey, messageParameters); 125 return putMessageInMap(warningMessages, propertyName, message, true, true); 126 } 127 128 public AutoPopulatingList<ErrorMessage> putInfo(String propertyName, String messageKey, 129 String... messageParameters) { 130 ErrorMessage message = new ErrorMessage(messageKey, messageParameters); 131 return putMessageInMap(infoMessages, propertyName, message, true, true); 132 } 133 134 public AutoPopulatingList<ErrorMessage> putError(String propertyName, ErrorMessage message) { 135 return putMessageInMap(errorMessages, propertyName, message, true, true); 136 } 137 138 public AutoPopulatingList<ErrorMessage> putWarning(String propertyName, ErrorMessage message) { 139 return putMessageInMap(warningMessages, propertyName, message, true, true); 140 } 141 142 public AutoPopulatingList<ErrorMessage> putInfo(String propertyName, ErrorMessage message) { 143 return putMessageInMap(infoMessages, propertyName, message, true, true); 144 } 145 146 public AutoPopulatingList<ErrorMessage> putErrorWithoutFullErrorPath(String propertyName, String errorKey, 147 String... errorParameters) { 148 ErrorMessage message = new ErrorMessage(errorKey, errorParameters); 149 return putMessageInMap(errorMessages, propertyName, message, false, true); 150 } 151 152 public AutoPopulatingList<ErrorMessage> putWarningWithoutFullErrorPath(String propertyName, String messageKey, 153 String... messageParameters) { 154 ErrorMessage message = new ErrorMessage(messageKey, messageParameters); 155 return putMessageInMap(warningMessages, propertyName, message, false, true); 156 } 157 158 public AutoPopulatingList<ErrorMessage> putInfoWithoutFullErrorPath(String propertyName, String messageKey, 159 String... messageParameters) { 160 ErrorMessage message = new ErrorMessage(messageKey, messageParameters); 161 return putMessageInMap(infoMessages, propertyName, message, false, true); 162 } 163 164 public AutoPopulatingList<ErrorMessage> putErrorWithoutFullErrorPath(String propertyName, ErrorMessage message) { 165 return putMessageInMap(errorMessages, propertyName, message, false, true); 166 } 167 168 public AutoPopulatingList<ErrorMessage> putWarningWithoutFullErrorPath(String propertyName, ErrorMessage message) { 169 return putMessageInMap(warningMessages, propertyName, message, false, true); 170 } 171 172 public AutoPopulatingList<ErrorMessage> putInfoWithoutFullErrorPath(String propertyName, ErrorMessage message) { 173 return putMessageInMap(infoMessages, propertyName, message, false, true); 174 } 175 176 public AutoPopulatingList<ErrorMessage> putErrorForSectionId(String sectionId, String errorKey, 177 String... errorParameters) { 178 return putErrorWithoutFullErrorPath(sectionId, errorKey, errorParameters); 179 } 180 181 public AutoPopulatingList<ErrorMessage> putWarningForSectionId(String sectionId, String messageKey, 182 String... messageParameters) { 183 return putWarningWithoutFullErrorPath(sectionId, messageKey, messageParameters); 184 } 185 186 public AutoPopulatingList<ErrorMessage> putInfoForSectionId(String sectionId, String messageKey, 187 String... messageParameters) { 188 return putInfoWithoutFullErrorPath(sectionId, messageKey, messageParameters); 189 } 190 191 public AutoPopulatingList<ErrorMessage> putErrorForSectionId(String sectionId, ErrorMessage message) { 192 return putErrorWithoutFullErrorPath(sectionId, message); 193 } 194 195 public AutoPopulatingList<ErrorMessage> putWarningForSectionId(String sectionId, ErrorMessage message) { 196 return putWarningWithoutFullErrorPath(sectionId, message); 197 } 198 199 public AutoPopulatingList<ErrorMessage> putInfoForSectionId(String sectionId, ErrorMessage message) { 200 return putInfoWithoutFullErrorPath(sectionId, message); 201 } 202 203 /** 204 * Adds a growl (using the default theme) to the message map with the given title and message 205 * 206 * @param growlTitle - title for the growl 207 * @param messageKey - key for the message in resources 208 * @param messageParameters - parameters for the message 209 */ 210 public void addGrowlMessage(String growlTitle, String messageKey, String... messageParameters) { 211 GrowlMessage growl = new GrowlMessage(); 212 213 growl.setTitle(growlTitle); 214 growl.setMessageKey(messageKey); 215 growl.setMessageParameters(messageParameters); 216 217 growlMessages.add(growl); 218 } 219 220 /** 221 * Add a growl to the message map 222 * 223 * @param growl - growl instance to add 224 */ 225 public void addGrowlMessage(GrowlMessage growl) { 226 growlMessages.add(growl); 227 } 228 229 /** 230 * Adds an error message to the given message map, adjusting the error path and message parameters if necessary 231 * 232 * @param messagesMap 233 * @param propertyName name of the property to add error under 234 * @param errorMessage 235 * @param prependFullErrorPath true if you want the whole parent error path prepended, false otherwise 236 * @param escapeHtmlMessageParameters whether to escape HTML characters in the message parameters, provides 237 * protection against XSS attacks 238 * @return TypeArrayList 239 */ 240 protected AutoPopulatingList<ErrorMessage> putMessageInMap(Map<String, AutoPopulatingList<ErrorMessage>> messagesMap, 241 String propertyName, ErrorMessage errorMessage, boolean prependFullErrorPath, 242 boolean escapeHtmlMessageParameters) { 243 if (StringUtils.isBlank(propertyName)) { 244 throw new IllegalArgumentException("invalid (blank) propertyName"); 245 } 246 if (StringUtils.isBlank(errorMessage.getErrorKey())) { 247 throw new IllegalArgumentException("invalid (blank) errorKey"); 248 } 249 250 // check if we have previous errors for this property 251 AutoPopulatingList<ErrorMessage> errorList = null; 252 String propertyKey = getKeyPath(propertyName, prependFullErrorPath); 253 if (messagesMap.containsKey(propertyKey)) { 254 errorList = messagesMap.get(propertyKey); 255 } else { 256 errorList = new AutoPopulatingList<ErrorMessage>(ErrorMessage.class); 257 } 258 259 if (escapeHtmlMessageParameters) { 260 if (errorMessage.getMessageParameters() != null) { 261 String[] filteredMessageParameters = new String[errorMessage.getMessageParameters().length]; 262 for (int i = 0; i < errorMessage.getMessageParameters().length; i++) { 263 filteredMessageParameters[i] = StringEscapeUtils.escapeHtml(errorMessage.getMessageParameters()[i]); 264 } 265 errorMessage.setMessageParameters(filteredMessageParameters); 266 } 267 268 if (errorMessage.getMessagePrefixParameters() != null) { 269 String[] filteredMessageParameters = new String[errorMessage.getMessagePrefixParameters().length]; 270 for (int i = 0; i < errorMessage.getMessagePrefixParameters().length; i++) { 271 filteredMessageParameters[i] = StringEscapeUtils.escapeHtml( 272 errorMessage.getMessagePrefixParameters()[i]); 273 } 274 errorMessage.setMessagePrefixParameters(filteredMessageParameters); 275 } 276 277 if (errorMessage.getMessageSuffixParameters() != null) { 278 String[] filteredMessageParameters = new String[errorMessage.getMessageSuffixParameters().length]; 279 for (int i = 0; i < errorMessage.getMessageSuffixParameters().length; i++) { 280 filteredMessageParameters[i] = StringEscapeUtils.escapeHtml( 281 errorMessage.getMessageSuffixParameters()[i]); 282 } 283 errorMessage.setMessageSuffixParameters(filteredMessageParameters); 284 } 285 } 286 287 // check if this error has already been added to the list 288 boolean alreadyAdded = false; 289 for (ErrorMessage e : errorList) { 290 if (e.equals(errorMessage)) { 291 alreadyAdded = true; 292 break; 293 } 294 } 295 if (!alreadyAdded) { 296 errorList.add(errorMessage); 297 } 298 299 return messagesMap.put(propertyKey, errorList); 300 } 301 302 /** 303 * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages 304 * will be replaced with a new ErrorMessage with the given replaceKey and replaceParameters. 305 * 306 * @param propertyName name of the property where existing error will be replaced 307 * @param targetKey error key of message to be replaced 308 * @param replaceParameters zero or more string parameters for the replacement error message 309 * @return true if the replacement occurred 310 * @paran replaceKey error key which will replace targetKey 311 */ 312 public boolean replaceError(String propertyName, String targetKey, String replaceKey, String... replaceParameters) { 313 return replaceError(propertyName, targetKey, true, replaceKey, replaceParameters); 314 } 315 316 /** 317 * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages 318 * will be replaced with a new ErrorMessage with the given replaceKey and replaceParameters. The targetKey 319 * and replaceKey will be prepended with the current errorPath, if any. 320 * 321 * @param propertyName name of the property where existing error will be replaced 322 * @param targetKey error key of message to be replaced 323 * @param replaceParameters zero or more string parameters for the replacement error message 324 * @return true if the replacement occurred 325 * @paran replaceKey error key which will replace targetKey 326 */ 327 public boolean replaceErrorWithoutFullErrorPath(String propertyName, String targetKey, String replaceKey, 328 String... replaceParameters) { 329 return replaceError(propertyName, targetKey, false, replaceKey, replaceParameters); 330 } 331 332 /** 333 * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages 334 * will be replaced with a new ErrorMessage with the given replaceKey and replaceParameters. 335 * 336 * @param propertyName name of the property to add error under 337 * @param targetKey resource key used to retrieve the error text 338 * @param withFullErrorPath true if you want the whole parent error path appended, false otherwise 339 * @param replaceParameters zero or more string parameters for the displayed error message 340 * @return true if the replacement occurred 341 */ 342 private boolean replaceError(String propertyName, String targetKey, boolean withFullErrorPath, String replaceKey, 343 String... replaceParameters) { 344 boolean replaced = false; 345 346 if (StringUtils.isBlank(propertyName)) { 347 throw new IllegalArgumentException("invalid (blank) propertyName"); 348 } 349 if (StringUtils.isBlank(targetKey)) { 350 throw new IllegalArgumentException("invalid (blank) targetKey"); 351 } 352 if (StringUtils.isBlank(replaceKey)) { 353 throw new IllegalArgumentException("invalid (blank) replaceKey"); 354 } 355 356 // check if we have previous errors for this property 357 AutoPopulatingList<ErrorMessage> errorList = null; 358 String propertyKey = getKeyPath(propertyName, withFullErrorPath); 359 if (errorMessages.containsKey(propertyKey)) { 360 errorList = errorMessages.get(propertyKey); 361 362 // look for the specific targetKey 363 for (int i = 0; i < errorList.size(); ++i) { 364 ErrorMessage em = errorList.get(i); 365 366 // replace matching messages 367 if (em.getErrorKey().equals(targetKey)) { 368 ErrorMessage rm = new ErrorMessage(replaceKey, replaceParameters); 369 errorList.set(i, rm); 370 replaced = true; 371 } 372 } 373 } 374 375 return replaced; 376 } 377 378 /** 379 * Returns true if the named field has a message with the given errorKey 380 * 381 * @param errorKey 382 * @param fieldName 383 * @return boolean 384 */ 385 public boolean fieldHasMessage(String fieldName, String errorKey) { 386 boolean found = false; 387 388 List<ErrorMessage> fieldMessages = errorMessages.get(fieldName); 389 if (fieldMessages != null) { 390 for (Iterator<ErrorMessage> i = fieldMessages.iterator(); !found && i.hasNext(); ) { 391 ErrorMessage errorMessage = i.next(); 392 found = errorMessage.getErrorKey().equals(errorKey); 393 } 394 } 395 396 return found; 397 } 398 399 /** 400 * Returns the number of messages for the given field 401 * 402 * @param fieldName 403 * @return int 404 */ 405 public int countFieldMessages(String fieldName) { 406 int count = 0; 407 408 List<ErrorMessage> fieldMessages = errorMessages.get(fieldName); 409 if (fieldMessages != null) { 410 count = fieldMessages.size(); 411 } 412 413 return count; 414 } 415 416 /** 417 * @return true if the given messageKey is associated with some property in this ErrorMap 418 */ 419 public boolean containsMessageKey(String messageKey) { 420 ErrorMessage foundMessage = null; 421 422 if (!hasNoErrors()) { 423 for (Iterator<Map.Entry<String, AutoPopulatingList<ErrorMessage>>> i = 424 getAllPropertiesAndErrors().iterator(); (foundMessage == null) && i.hasNext(); ) { 425 Map.Entry<String, AutoPopulatingList<ErrorMessage>> e = i.next(); 426 AutoPopulatingList<ErrorMessage> entryErrorList = e.getValue(); 427 for (Iterator<ErrorMessage> j = entryErrorList.iterator(); j.hasNext(); ) { 428 ErrorMessage em = j.next(); 429 if (messageKey.equals(em.getErrorKey())) { 430 foundMessage = em; 431 } 432 } 433 } 434 } 435 436 return (foundMessage != null); 437 } 438 439 private int getMessageCount(Map<String, AutoPopulatingList<ErrorMessage>> messageMap) { 440 int messageCount = 0; 441 for (Iterator<String> iter = messageMap.keySet().iterator(); iter.hasNext(); ) { 442 String errorKey = iter.next(); 443 List<ErrorMessage> errors = messageMap.get(errorKey); 444 messageCount += errors.size(); 445 } 446 447 return messageCount; 448 } 449 450 /** 451 * Counts the total number of error messages in the map 452 * 453 * @return returns an int for the total number of errors 454 */ 455 public int getErrorCount() { 456 return getMessageCount(errorMessages); 457 } 458 459 /** 460 * Counts the total number of warning messages in the map 461 * 462 * @return returns an int for the total number of warnings 463 */ 464 public int getWarningCount() { 465 return getMessageCount(warningMessages); 466 } 467 468 /** 469 * Counts the total number of info messages in the map 470 * 471 * @return returns an int for the total number of info 472 */ 473 public int getInfoCount() { 474 return getMessageCount(infoMessages); 475 } 476 477 /** 478 * @param path 479 * @return Returns a List of ErrorMessages for the given path 480 */ 481 public AutoPopulatingList<ErrorMessage> getMessages(String path) { 482 return errorMessages.get(path); 483 } 484 485 /** 486 * Adds a string prefix to the error path. 487 * 488 * @param parentName 489 */ 490 public void addToErrorPath(String parentName) { 491 errorPath.add(parentName); 492 } 493 494 /** 495 * This method returns the list that holds the error path values. 496 * 497 * @return List 498 */ 499 public List<String> getErrorPath() { 500 return errorPath; 501 } 502 503 /** 504 * Removes a string prefix from the error path. 505 * 506 * @param parentName 507 * @return boolean Returns true if the parentName existed, false otherwise. 508 */ 509 public boolean removeFromErrorPath(String parentName) { 510 return errorPath.remove(parentName); 511 } 512 513 /** 514 * Clears the errorPath. 515 */ 516 public void clearErrorPath() { 517 errorPath.clear(); 518 } 519 520 /** 521 * This is what's prepended to the beginning of the key. This is built by iterating over all of the entries in the 522 * errorPath 523 * list and concatenating them together with a "." 524 * 525 * @param propertyName 526 * @param prependFullErrorPath 527 * @return String Returns the keyPath. 528 */ 529 public String getKeyPath(String propertyName, boolean prependFullErrorPath) { 530 String keyPath = ""; 531 532 if (KRADConstants.GLOBAL_ERRORS.equals(propertyName)) { 533 return KRADConstants.GLOBAL_ERRORS; 534 } 535 536 if (!errorPath.isEmpty() && prependFullErrorPath) { 537 keyPath = StringUtils.join(errorPath.iterator(), "."); 538 keyPath += (keyPath != null && keyPath.endsWith(".")) ? propertyName : "." + propertyName; 539 } else { 540 keyPath = propertyName; 541 } 542 543 return keyPath; 544 } 545 546 /** 547 * @return List of the property names that have errors. 548 */ 549 public List<String> getPropertiesWithErrors() { 550 List<String> properties = new ArrayList<String>(); 551 552 for (Iterator<String> iter = errorMessages.keySet().iterator(); iter.hasNext(); ) { 553 properties.add(iter.next()); 554 } 555 556 return properties; 557 } 558 559 /** 560 * @return List of the property names that have warnings. 561 */ 562 public List<String> getPropertiesWithWarnings() { 563 List<String> properties = new ArrayList<String>(warningMessages.keySet()); 564 return properties; 565 } 566 567 /** 568 * @return List of the property names that have info. 569 */ 570 public List<String> getPropertiesWithInfo() { 571 List<String> properties = new ArrayList<String>(infoMessages.keySet()); 572 return properties; 573 } 574 575 public void clearErrorMessages() { 576 errorMessages.clear(); 577 } 578 579 public boolean doesPropertyHaveError(String key) { 580 return errorMessages.containsKey(key); 581 } 582 583 /** 584 * @param pattern comma separated list of keys, optionally ending with * wildcard 585 */ 586 public boolean containsKeyMatchingPattern(String pattern) { 587 List<String> simplePatterns = new ArrayList<String>(); 588 List<String> wildcardPatterns = new ArrayList<String>(); 589 String[] patterns = pattern.split(","); 590 for (int i = 0; i < patterns.length; i++) { 591 String s = patterns[i]; 592 if (s.endsWith("*")) { 593 wildcardPatterns.add(s.substring(0, s.length() - 1)); 594 } else { 595 simplePatterns.add(s); 596 } 597 } 598 for (Iterator<String> keys = errorMessages.keySet().iterator(); keys.hasNext(); ) { 599 String key = keys.next(); 600 if (simplePatterns.contains(key)) { 601 return true; 602 } 603 for (Iterator<String> wildcardIterator = wildcardPatterns.iterator(); wildcardIterator.hasNext(); ) { 604 String wildcard = wildcardIterator.next(); 605 if (key.startsWith(wildcard)) { 606 return true; 607 } 608 } 609 } 610 return false; 611 } 612 613 public Set<Map.Entry<String, AutoPopulatingList<ErrorMessage>>> getAllPropertiesAndErrors() { 614 return errorMessages.entrySet(); 615 } 616 617 public AutoPopulatingList<ErrorMessage> getErrorMessagesForProperty(String propertyName) { 618 return errorMessages.get(propertyName); 619 } 620 621 public AutoPopulatingList<ErrorMessage> getWarningMessagesForProperty(String propertyName) { 622 return warningMessages.get(propertyName); 623 } 624 625 public AutoPopulatingList<ErrorMessage> getInfoMessagesForProperty(String propertyName) { 626 return infoMessages.get(propertyName); 627 } 628 629 /** 630 * Gets a list of lists that represent errors that matched by the 631 * propertyName passed in (multiple lists because the wildcard can match 632 * multiple keys). If wildcard is true, the propertyName ends with a 633 * wildcard character. Otherwise, it will only match on the single key and 634 * return a list with one list 635 * 636 * @param propertyName 637 * @param allowWildcard 638 * @return 639 */ 640 public List<AutoPopulatingList<ErrorMessage>> getErrorMessagesForProperty(String propertyName, 641 boolean allowWildcard) { 642 List<AutoPopulatingList<ErrorMessage>> foundMessages = new ArrayList<AutoPopulatingList<ErrorMessage>>(); 643 if (allowWildcard) { 644 boolean wildcard = false; 645 if (propertyName.endsWith("*")) { 646 wildcard = true; 647 propertyName = propertyName.substring(0, propertyName.length() - 1); 648 } 649 for (Iterator<String> keys = errorMessages.keySet().iterator(); keys.hasNext(); ) { 650 String key = keys.next(); 651 if (!wildcard && propertyName.equals(key)) { 652 foundMessages.add(errorMessages.get(key)); 653 break; 654 } else if (wildcard && key.startsWith(propertyName)) { 655 foundMessages.add(errorMessages.get(key)); 656 } 657 } 658 } else { 659 foundMessages.add(getErrorMessagesForProperty(propertyName)); 660 } 661 662 return foundMessages; 663 } 664 665 /** 666 * Gets a list of lists that represent warnings that matched by the 667 * propertyName passed in (multiple lists because the wildcard can match 668 * multiple keys). If wildcard is true, the propertyName ends with a 669 * wildcard character. Otherwise, it will only match on the single key and 670 * return a list with one list. 671 * 672 * @param propertyName 673 * @param allowWildcard 674 * @return 675 */ 676 public List<AutoPopulatingList<ErrorMessage>> getWarningMessagesForProperty(String propertyName, 677 boolean allowWildcard) { 678 List<AutoPopulatingList<ErrorMessage>> foundMessages = new ArrayList<AutoPopulatingList<ErrorMessage>>(); 679 if (allowWildcard) { 680 boolean wildcard = false; 681 if (propertyName.endsWith("*")) { 682 wildcard = true; 683 propertyName = propertyName.substring(0, propertyName.length() - 1); 684 } 685 for (Iterator<String> keys = warningMessages.keySet().iterator(); keys.hasNext(); ) { 686 String key = keys.next(); 687 if (!wildcard && propertyName.equals(key)) { 688 foundMessages.add(warningMessages.get(key)); 689 break; 690 } else if (wildcard && key.startsWith(propertyName)) { 691 foundMessages.add(warningMessages.get(key)); 692 } 693 } 694 } else { 695 foundMessages.add(getWarningMessagesForProperty(propertyName)); 696 } 697 698 return foundMessages; 699 } 700 701 /** 702 * Gets a list of lists that represent info messages that matched by the 703 * propertyName passed in (multiple lists because the wildcard can match 704 * multiple keys). If wildcard is true, the propertyName ends with a 705 * wildcard character. If it is false, it will only match on the single key 706 * and return a list with one list. 707 * 708 * @param propertyName 709 * @param allowWildcard 710 * @return 711 */ 712 public List<AutoPopulatingList<ErrorMessage>> getInfoMessagesForProperty(String propertyName, 713 boolean allowWildcard) { 714 List<AutoPopulatingList<ErrorMessage>> foundMessages = new ArrayList<AutoPopulatingList<ErrorMessage>>(); 715 if (allowWildcard) { 716 boolean wildcard = false; 717 if (propertyName.endsWith("*")) { 718 wildcard = true; 719 propertyName = propertyName.substring(0, propertyName.length() - 1); 720 } 721 for (Iterator<String> keys = infoMessages.keySet().iterator(); keys.hasNext(); ) { 722 String key = keys.next(); 723 if (!wildcard && propertyName.equals(key)) { 724 foundMessages.add(infoMessages.get(key)); 725 break; 726 } else if (wildcard && key.startsWith(propertyName)) { 727 foundMessages.add(infoMessages.get(key)); 728 } 729 } 730 } else { 731 foundMessages.add(getInfoMessagesForProperty(propertyName)); 732 } 733 734 return foundMessages; 735 } 736 737 public boolean hasErrors() { 738 return !errorMessages.isEmpty(); 739 } 740 741 public boolean hasNoErrors() { 742 return errorMessages.isEmpty(); 743 } 744 745 public boolean hasWarnings() { 746 return !warningMessages.isEmpty(); 747 } 748 749 public boolean hasNoWarnings() { 750 return warningMessages.isEmpty(); 751 } 752 753 public boolean hasInfo() { 754 return !infoMessages.isEmpty(); 755 } 756 757 public boolean hasNoInfo() { 758 return infoMessages.isEmpty(); 759 } 760 761 public boolean hasMessages() { 762 if (!errorMessages.isEmpty() || !warningMessages.isEmpty() || !infoMessages.isEmpty()) { 763 return true; 764 } 765 return false; 766 } 767 768 public boolean hasNoMessages() { 769 if (errorMessages.isEmpty() && warningMessages.isEmpty() && infoMessages.isEmpty()) { 770 return true; 771 } 772 return false; 773 } 774 775 public Set<String> getAllPropertiesWithErrors() { 776 return errorMessages.keySet(); 777 } 778 779 public Set<String> getAllPropertiesWithWarnings() { 780 return warningMessages.keySet(); 781 } 782 783 public Set<String> getAllPropertiesWithInfo() { 784 return infoMessages.keySet(); 785 } 786 787 public AutoPopulatingList<ErrorMessage> removeAllErrorMessagesForProperty(String property) { 788 return errorMessages.remove(property); 789 } 790 791 public AutoPopulatingList<ErrorMessage> removeAllWarningMessagesForProperty(String property) { 792 return warningMessages.remove(property); 793 } 794 795 public AutoPopulatingList<ErrorMessage> removeAllInfoMessagesForProperty(String property) { 796 return infoMessages.remove(property); 797 } 798 799 public int getNumberOfPropertiesWithErrors() { 800 return errorMessages.size(); 801 } 802 803 public Map<String, AutoPopulatingList<ErrorMessage>> getErrorMessages() { 804 return this.errorMessages; 805 } 806 807 public Map<String, AutoPopulatingList<ErrorMessage>> getWarningMessages() { 808 return this.warningMessages; 809 } 810 811 public Map<String, AutoPopulatingList<ErrorMessage>> getInfoMessages() { 812 return this.infoMessages; 813 } 814 815 /** 816 * Returns the list of growl messages (@{link GrowlMessage}) that have been added to 817 * the message map 818 * 819 * @return List<GrowlMessage> 820 */ 821 public List<GrowlMessage> getGrowlMessages() { 822 return this.growlMessages; 823 } 824 825 @Override 826 public boolean equals(Object o) { 827 return EqualsBuilder.reflectionEquals(this, o); 828 } 829 830 @Override 831 public int hashCode() { 832 return HashCodeBuilder.reflectionHashCode(this); 833 } 834 835 @Override 836 public String toString() { 837 return ToStringBuilder.reflectionToString(this); 838 } 839}