All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kuali.rice.krad.util.MessageMap Maven / Gradle / Ivy

There is a newer version: 2.6.2
Show newest version
/**
 * Copyright 2005-2016 The Kuali Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.opensource.org/licenses/ecl2.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.kuali.rice.krad.util;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.springframework.util.AutoPopulatingList;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Holds errors due to validation
 *
 * 

Keys of map represent property paths, and value is a AutoPopulatingList that contains resource string * keys (to retrieve the error message).

* *

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

* * @author Kuali Rice Team ([email protected]) */ public class MessageMap implements Serializable { private static final long serialVersionUID = -2328635367656516150L; private final List errorPath; private final Map> errorMessages; private final Map> warningMessages; private final Map> infoMessages; private final List growlMessages; public MessageMap() { errorPath = Collections.synchronizedList(new ArrayList()); errorMessages = Collections.synchronizedMap(new LinkedHashMap>()); warningMessages = Collections.synchronizedMap(new LinkedHashMap>()); infoMessages = Collections.synchronizedMap(new LinkedHashMap>()); growlMessages = Collections.synchronizedList(new AutoPopulatingList(GrowlMessage.class)); } public MessageMap(MessageMap messageMap) { this.errorPath = messageMap.errorPath; this.errorMessages = messageMap.errorMessages; this.warningMessages = messageMap.warningMessages; this.infoMessages = messageMap.infoMessages; growlMessages = Collections.synchronizedList(new AutoPopulatingList(GrowlMessage.class)); } public void merge(MessageMap messageMap) { if (messageMap != null) { if (messageMap.hasErrors()) { merge(messageMap.getErrorMessages(), errorMessages); } if (messageMap.hasInfo()) { merge(messageMap.getInfoMessages(), infoMessages); } if (messageMap.hasWarnings()) { merge(messageMap.getWarningMessages(), warningMessages); } if (messageMap.getGrowlMessages() != null) { growlMessages.addAll(messageMap.getGrowlMessages()); } } } /** * Takes one message map and merges it into another. Makes sure there are no duplicates. * * @param messagesFrom * @param messagesTo * TODO: This method is not thread-safe and should be private. */ public void merge(Map> messagesFrom, Map> messagesTo) { for (String key : messagesFrom.keySet()) { if (messagesTo.containsKey(key)) { // now we need to merge the messages List tal = messagesFrom.get(key); List parentList = messagesTo.get(key); for (Object o : tal) { if (!parentList.contains(o)) { parentList.add((ErrorMessage) o); } } } else { messagesTo.put(key, messagesFrom.get(key)); } } } public List putError(String propertyName, String errorKey, String... errorParameters) { ErrorMessage message = new ErrorMessage(errorKey, errorParameters); return putMessageInMap(errorMessages, propertyName, message, true, true); } public List putWarning(String propertyName, String messageKey, String... messageParameters) { ErrorMessage message = new ErrorMessage(messageKey, messageParameters); return putMessageInMap(warningMessages, propertyName, message, true, true); } public List putInfo(String propertyName, String messageKey, String... messageParameters) { ErrorMessage message = new ErrorMessage(messageKey, messageParameters); return putMessageInMap(infoMessages, propertyName, message, true, true); } public List putError(String propertyName, ErrorMessage message) { return putMessageInMap(errorMessages, propertyName, message, true, true); } public List putWarning(String propertyName, ErrorMessage message) { return putMessageInMap(warningMessages, propertyName, message, true, true); } public List putInfo(String propertyName, ErrorMessage message) { return putMessageInMap(infoMessages, propertyName, message, true, true); } public List putErrorWithoutFullErrorPath(String propertyName, String errorKey, String... errorParameters) { ErrorMessage message = new ErrorMessage(errorKey, errorParameters); return putMessageInMap(errorMessages, propertyName, message, false, true); } public List putWarningWithoutFullErrorPath(String propertyName, String messageKey, String... messageParameters) { ErrorMessage message = new ErrorMessage(messageKey, messageParameters); return putMessageInMap(warningMessages, propertyName, message, false, true); } public List putInfoWithoutFullErrorPath(String propertyName, String messageKey, String... messageParameters) { ErrorMessage message = new ErrorMessage(messageKey, messageParameters); return putMessageInMap(infoMessages, propertyName, message, false, true); } public List putErrorWithoutFullErrorPath(String propertyName, ErrorMessage message) { return putMessageInMap(errorMessages, propertyName, message, false, true); } public List putWarningWithoutFullErrorPath(String propertyName, ErrorMessage message) { return putMessageInMap(warningMessages, propertyName, message, false, true); } public List putInfoWithoutFullErrorPath(String propertyName, ErrorMessage message) { return putMessageInMap(infoMessages, propertyName, message, false, true); } public List putErrorForSectionId(String sectionId, String errorKey, String... errorParameters) { return putErrorWithoutFullErrorPath(sectionId, errorKey, errorParameters); } public List putWarningForSectionId(String sectionId, String messageKey, String... messageParameters) { return putWarningWithoutFullErrorPath(sectionId, messageKey, messageParameters); } public List putInfoForSectionId(String sectionId, String messageKey, String... messageParameters) { return putInfoWithoutFullErrorPath(sectionId, messageKey, messageParameters); } public List putErrorForSectionId(String sectionId, ErrorMessage message) { return putErrorWithoutFullErrorPath(sectionId, message); } public List putWarningForSectionId(String sectionId, ErrorMessage message) { return putWarningWithoutFullErrorPath(sectionId, message); } public List putInfoForSectionId(String sectionId, ErrorMessage message) { return putInfoWithoutFullErrorPath(sectionId, message); } /** * Creates error message given the error key and parameters and adds it to the message map. * * @param propertyName name of the property associated with the error * @param errorKey message key for the error * @param escapeHtmlMessageParameters whether to escape HTML characters in the message parameters * @param errorParameters zero or more parameters for the message text * @return TypeArrayList */ public List putError(String propertyName, String errorKey, Boolean escapeHtmlMessageParameters, String... errorParameters) { ErrorMessage message = new ErrorMessage(errorKey, errorParameters); return putMessageInMap(errorMessages, propertyName, message, true, escapeHtmlMessageParameters); } /** * Creates error message given the message key and parameters and adds it to the warning message map. * * @param propertyName name of the property associated with the warning * @param messageKey message key for the error * @param escapeHtmlMessageParameters whether to escape HTML characters in the message parameters * @param messageParameters zero or more parameters for the message text * @return TypeArrayList */ public List putWarning(String propertyName, String messageKey, Boolean escapeHtmlMessageParameters, String... messageParameters) { ErrorMessage message = new ErrorMessage(messageKey, messageParameters); return putMessageInMap(warningMessages, propertyName, message, true, escapeHtmlMessageParameters); } /** * Creates error message given the message key and parameters and adds it to the info message map. * * @param propertyName name of the property associated with the info * @param messageKey message key for the info * @param escapeHtmlMessageParameters whether to escape HTML characters in the message parameters * @param messageParameters zero or more parameters for the message text * @return TypeArrayList */ public List putInfo(String propertyName, String messageKey, Boolean escapeHtmlMessageParameters, String... messageParameters) { ErrorMessage message = new ErrorMessage(messageKey, messageParameters); return putMessageInMap(infoMessages, propertyName, message, true, escapeHtmlMessageParameters); } /** * Adds a growl (using the default theme) to the message map with the given title and message * * @param growlTitle - title for the growl * @param messageKey - key for the message in resources * @param messageParameters - parameters for the message */ public void addGrowlMessage(String growlTitle, String messageKey, String... messageParameters) { GrowlMessage growl = new GrowlMessage(); growl.setTitle(growlTitle); growl.setMessageKey(messageKey); growl.setMessageParameters(messageParameters); growlMessages.add(growl); } /** * Add a growl to the message map * * @param growl - growl instance to add */ public void addGrowlMessage(GrowlMessage growl) { growlMessages.add(growl); } /** * Adds an error message to the given message map, adjusting the error path and message parameters if necessary * * @param messagesMap * @param propertyName name of the property to add error under * @param errorMessage * @param prependFullErrorPath true if you want the whole parent error path prepended, false otherwise * @param escapeHtmlMessageParameters whether to escape HTML characters in the message parameters, provides * protection against XSS attacks * @return TypeArrayList */ protected List putMessageInMap(Map> messagesMap, String propertyName, ErrorMessage errorMessage, boolean prependFullErrorPath, boolean escapeHtmlMessageParameters) { if (StringUtils.isBlank(propertyName)) { throw new IllegalArgumentException("invalid (blank) propertyName"); } if (StringUtils.isBlank(errorMessage.getErrorKey())) { throw new IllegalArgumentException("invalid (blank) errorKey"); } // check if we have previous errors for this property List errorList = null; String propertyKey = getKeyPath(propertyName, prependFullErrorPath); if (messagesMap.containsKey(propertyKey)) { errorList = messagesMap.get(propertyKey); } else { errorList = Collections.synchronizedList(new AutoPopulatingList(ErrorMessage.class)); } if (escapeHtmlMessageParameters) { if (errorMessage.getMessageParameters() != null) { String[] filteredMessageParameters = new String[errorMessage.getMessageParameters().length]; for (int i = 0; i < errorMessage.getMessageParameters().length; i++) { filteredMessageParameters[i] = StringEscapeUtils.escapeHtml(errorMessage.getMessageParameters()[i]); } errorMessage.setMessageParameters(filteredMessageParameters); } if (errorMessage.getMessagePrefixParameters() != null) { String[] filteredMessageParameters = new String[errorMessage.getMessagePrefixParameters().length]; for (int i = 0; i < errorMessage.getMessagePrefixParameters().length; i++) { filteredMessageParameters[i] = StringEscapeUtils.escapeHtml( errorMessage.getMessagePrefixParameters()[i]); } errorMessage.setMessagePrefixParameters(filteredMessageParameters); } if (errorMessage.getMessageSuffixParameters() != null) { String[] filteredMessageParameters = new String[errorMessage.getMessageSuffixParameters().length]; for (int i = 0; i < errorMessage.getMessageSuffixParameters().length; i++) { filteredMessageParameters[i] = StringEscapeUtils.escapeHtml( errorMessage.getMessageSuffixParameters()[i]); } errorMessage.setMessageSuffixParameters(filteredMessageParameters); } } // check if this error has already been added to the list boolean alreadyAdded = false; for (ErrorMessage e : errorList) { if (e.equals(errorMessage)) { alreadyAdded = true; break; } } if (!alreadyAdded) { errorList.add(errorMessage); } return messagesMap.put(propertyKey, errorList); } /** * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages * will be replaced with a new ErrorMessage with the given replaceKey and replaceParameters. * * @param propertyName name of the property where existing error will be replaced * @param targetKey error key of message to be replaced * @param replaceParameters zero or more string parameters for the replacement error message * @return true if the replacement occurred * @paran replaceKey error key which will replace targetKey */ public boolean replaceError(String propertyName, String targetKey, String replaceKey, String... replaceParameters) { return replaceError(propertyName, targetKey, true, replaceKey, replaceParameters); } /** * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages * will be replaced with a new ErrorMessage with the given replaceKey and replaceParameters. The targetKey * and replaceKey will be prepended with the current errorPath, if any. * * @param propertyName name of the property where existing error will be replaced * @param targetKey error key of message to be replaced * @param replaceParameters zero or more string parameters for the replacement error message * @return true if the replacement occurred * @paran replaceKey error key which will replace targetKey */ public boolean replaceErrorWithoutFullErrorPath(String propertyName, String targetKey, String replaceKey, String... replaceParameters) { return replaceError(propertyName, targetKey, false, replaceKey, replaceParameters); } /** * If any error messages with the key targetKey exist in this ErrorMap for the named property, those ErrorMessages * will be replaced with a new ErrorMessage with the given replaceKey and replaceParameters. * * @param propertyName name of the property to add error under * @param targetKey resource key used to retrieve the error text * @param withFullErrorPath true if you want the whole parent error path appended, false otherwise * @param replaceParameters zero or more string parameters for the displayed error message * @return true if the replacement occurred */ private boolean replaceError(String propertyName, String targetKey, boolean withFullErrorPath, String replaceKey, String... replaceParameters) { boolean replaced = false; if (StringUtils.isBlank(propertyName)) { throw new IllegalArgumentException("invalid (blank) propertyName"); } if (StringUtils.isBlank(targetKey)) { throw new IllegalArgumentException("invalid (blank) targetKey"); } if (StringUtils.isBlank(replaceKey)) { throw new IllegalArgumentException("invalid (blank) replaceKey"); } // check if we have previous errors for this property List errorList = null; String propertyKey = getKeyPath(propertyName, withFullErrorPath); if (errorMessages.containsKey(propertyKey)) { errorList = errorMessages.get(propertyKey); // look for the specific targetKey for (int i = 0; i < errorList.size(); ++i) { ErrorMessage em = errorList.get(i); // replace matching messages if (em.getErrorKey().equals(targetKey)) { ErrorMessage rm = new ErrorMessage(replaceKey, replaceParameters); errorList.set(i, rm); replaced = true; } } } return replaced; } /** * Returns true if the named field has a message with the given errorKey * * @param errorKey * @param fieldName * @return boolean */ public boolean fieldHasMessage(String fieldName, String errorKey) { boolean found = false; List fieldMessages = errorMessages.get(fieldName); if (fieldMessages != null) { for (Iterator i = fieldMessages.iterator(); !found && i.hasNext(); ) { ErrorMessage errorMessage = i.next(); found = errorMessage.getErrorKey().equals(errorKey); } } return found; } /** * Returns the number of messages for the given field * * @param fieldName * @return int */ public int countFieldMessages(String fieldName) { int count = 0; List fieldMessages = errorMessages.get(fieldName); if (fieldMessages != null) { count = fieldMessages.size(); } return count; } /** * @return true if the given messageKey is associated with some property in this ErrorMap */ public boolean containsMessageKey(String messageKey) { ErrorMessage foundMessage = null; if (!hasNoErrors()) { for (Iterator>> i = getAllPropertiesAndErrors().iterator(); (foundMessage == null) && i.hasNext(); ) { Map.Entry> e = i.next(); List entryErrorList = e.getValue(); for (Iterator j = entryErrorList.iterator(); j.hasNext(); ) { ErrorMessage em = j.next(); if (messageKey.equals(em.getErrorKey())) { foundMessage = em; } } } } return (foundMessage != null); } private int getMessageCount(Map> messageMap) { int messageCount = 0; for (Iterator iter = messageMap.keySet().iterator(); iter.hasNext(); ) { String errorKey = iter.next(); List errors = messageMap.get(errorKey); messageCount += errors.size(); } return messageCount; } /** * Counts the total number of error messages in the map * * @return returns an int for the total number of errors */ public int getErrorCount() { return getMessageCount(errorMessages); } /** * Counts the total number of warning messages in the map * * @return returns an int for the total number of warnings */ public int getWarningCount() { return getMessageCount(warningMessages); } /** * Counts the total number of info messages in the map * * @return returns an int for the total number of info */ public int getInfoCount() { return getMessageCount(infoMessages); } /** * @param path * @return Returns a List of ErrorMessages for the given path */ public List getMessages(String path) { return errorMessages.get(path); } /** * Adds a string prefix to the error path. * * @param parentName */ public void addToErrorPath(String parentName) { errorPath.add(parentName); } /** * This method returns the list that holds the error path values. * * @return List */ public List getErrorPath() { return errorPath; } /** * Removes a string prefix from the error path. * * @param parentName * @return boolean Returns true if the parentName existed, false otherwise. */ public boolean removeFromErrorPath(String parentName) { return errorPath.remove(parentName); } /** * Clears the errorPath. */ public void clearErrorPath() { errorPath.clear(); } /** * This is what's prepended to the beginning of the key. This is built by iterating over all of the entries in the * errorPath * list and concatenating them together with a "." * * @param propertyName * @param prependFullErrorPath * @return String Returns the keyPath. */ public String getKeyPath(String propertyName, boolean prependFullErrorPath) { String keyPath = ""; if (KRADConstants.GLOBAL_ERRORS.equals(propertyName)) { return KRADConstants.GLOBAL_ERRORS; } if (!errorPath.isEmpty() && prependFullErrorPath) { keyPath = StringUtils.join(errorPath.iterator(), "."); keyPath += (keyPath != null && keyPath.endsWith(".")) ? propertyName : "." + propertyName; } else { keyPath = propertyName; } return keyPath; } /** * @return List of the property names that have errors. */ public List getPropertiesWithErrors() { List properties = new ArrayList(); for (Iterator iter = errorMessages.keySet().iterator(); iter.hasNext(); ) { properties.add(iter.next()); } return properties; } /** * @return List of the property names that have warnings. */ public List getPropertiesWithWarnings() { List properties = new ArrayList(warningMessages.keySet()); return properties; } /** * @return List of the property names that have info. */ public List getPropertiesWithInfo() { List properties = new ArrayList(infoMessages.keySet()); return properties; } public void clearErrorMessages() { errorMessages.clear(); } public boolean doesPropertyHaveError(String key) { return errorMessages.containsKey(key); } /** * @param pattern comma separated list of keys, optionally ending with * wildcard */ public boolean containsKeyMatchingPattern(String pattern) { List simplePatterns = new ArrayList(); List wildcardPatterns = new ArrayList(); String[] patterns = pattern.split(","); for (int i = 0; i < patterns.length; i++) { String s = patterns[i]; if (s.endsWith("*")) { wildcardPatterns.add(s.substring(0, s.length() - 1)); } else { simplePatterns.add(s); } } for (Iterator keys = errorMessages.keySet().iterator(); keys.hasNext(); ) { String key = keys.next(); if (simplePatterns.contains(key)) { return true; } for (Iterator wildcardIterator = wildcardPatterns.iterator(); wildcardIterator.hasNext(); ) { String wildcard = wildcardIterator.next(); if (key.startsWith(wildcard)) { return true; } } } return false; } public Set>> getAllPropertiesAndErrors() { return errorMessages.entrySet(); } public List getErrorMessagesForProperty(String propertyName) { return errorMessages.get(propertyName); } public List getWarningMessagesForProperty(String propertyName) { return warningMessages.get(propertyName); } public List getInfoMessagesForProperty(String propertyName) { return infoMessages.get(propertyName); } /** * Gets a list of lists that represent errors that matched by the * propertyName passed in (multiple lists because the wildcard can match * multiple keys). If wildcard is true, the propertyName ends with a * wildcard character. Otherwise, it will only match on the single key and * return a list with one list * * @param propertyName * @param allowWildcard * @return */ public List> getErrorMessagesForProperty(String propertyName, boolean allowWildcard) { List> foundMessages = new ArrayList>(); if (allowWildcard) { boolean wildcard = false; if (propertyName.endsWith("*")) { wildcard = true; propertyName = propertyName.substring(0, propertyName.length() - 1); } for (Iterator keys = errorMessages.keySet().iterator(); keys.hasNext(); ) { String key = keys.next(); if (!wildcard && propertyName.equals(key)) { foundMessages.add(errorMessages.get(key)); break; } else if (wildcard && key.startsWith(propertyName)) { foundMessages.add(errorMessages.get(key)); } } } else { foundMessages.add(getErrorMessagesForProperty(propertyName)); } return foundMessages; } /** * Gets a list of lists that represent warnings that matched by the * propertyName passed in (multiple lists because the wildcard can match * multiple keys). If wildcard is true, the propertyName ends with a * wildcard character. Otherwise, it will only match on the single key and * return a list with one list. * * @param propertyName * @param allowWildcard * @return */ public List> getWarningMessagesForProperty(String propertyName, boolean allowWildcard) { List> foundMessages = new ArrayList>(); if (allowWildcard) { boolean wildcard = false; if (propertyName.endsWith("*")) { wildcard = true; propertyName = propertyName.substring(0, propertyName.length() - 1); } for (Iterator keys = warningMessages.keySet().iterator(); keys.hasNext(); ) { String key = keys.next(); if (!wildcard && propertyName.equals(key)) { foundMessages.add(warningMessages.get(key)); break; } else if (wildcard && key.startsWith(propertyName)) { foundMessages.add(warningMessages.get(key)); } } } else { foundMessages.add(getWarningMessagesForProperty(propertyName)); } return foundMessages; } /** * Gets a list of lists that represent info messages that matched by the * propertyName passed in (multiple lists because the wildcard can match * multiple keys). If wildcard is true, the propertyName ends with a * wildcard character. If it is false, it will only match on the single key * and return a list with one list. * * @param propertyName * @param allowWildcard * @return */ public List> getInfoMessagesForProperty(String propertyName, boolean allowWildcard) { List> foundMessages = new ArrayList>(); if (allowWildcard) { boolean wildcard = false; if (propertyName.endsWith("*")) { wildcard = true; propertyName = propertyName.substring(0, propertyName.length() - 1); } for (Iterator keys = infoMessages.keySet().iterator(); keys.hasNext(); ) { String key = keys.next(); if (!wildcard && propertyName.equals(key)) { foundMessages.add(infoMessages.get(key)); break; } else if (wildcard && key.startsWith(propertyName)) { foundMessages.add(infoMessages.get(key)); } } } else { foundMessages.add(getInfoMessagesForProperty(propertyName)); } return foundMessages; } public boolean hasErrors() { return !errorMessages.isEmpty(); } public boolean hasNoErrors() { return errorMessages.isEmpty(); } public boolean hasWarnings() { return !warningMessages.isEmpty(); } public boolean hasNoWarnings() { return warningMessages.isEmpty(); } public boolean hasInfo() { return !infoMessages.isEmpty(); } public boolean hasNoInfo() { return infoMessages.isEmpty(); } public boolean hasMessages() { if (!errorMessages.isEmpty() || !warningMessages.isEmpty() || !infoMessages.isEmpty()) { return true; } return false; } public boolean hasNoMessages() { if (errorMessages.isEmpty() && warningMessages.isEmpty() && infoMessages.isEmpty()) { return true; } return false; } public Set getAllPropertiesWithErrors() { return errorMessages.keySet(); } public Set getAllPropertiesWithWarnings() { return warningMessages.keySet(); } public Set getAllPropertiesWithInfo() { return infoMessages.keySet(); } public List removeAllErrorMessagesForProperty(String property) { return errorMessages.remove(property); } public List removeAllWarningMessagesForProperty(String property) { return warningMessages.remove(property); } public List removeAllInfoMessagesForProperty(String property) { return infoMessages.remove(property); } public int getNumberOfPropertiesWithErrors() { return errorMessages.size(); } public Map> getErrorMessages() { return this.errorMessages; } public Map> getWarningMessages() { return this.warningMessages; } public Map> getInfoMessages() { return this.infoMessages; } /** * Returns the list of growl messages (@{link GrowlMessage}) that have been added to * the message map * * @return List */ public List getGrowlMessages() { return this.growlMessages; } @Override public boolean equals(Object o) { return EqualsBuilder.reflectionEquals(this, o); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy