/*==========================================================================*\ | $Id: ErrorDictionaryPanel.java,v 1.1 2010/05/11 14:51:55 aallowat Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2006-2009 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.core; import java.util.Enumeration; import com.webobjects.appserver.WOContext; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSMutableArray; import com.webobjects.foundation.NSMutableDictionary; import er.extensions.ERXExtensions; import er.extensions.eof.ERXGenericRecord; import er.extensions.localization.ERXLocalizer; //------------------------------------------------------------------------- /** * Provides a standard component for displaying error message(s) on * pages. This class is based significantly on * {@link er.extensions.components.ERXErrorDictionaryPanel}, but cannot be a * subclass of that component because of some of the behaviors it supports (the * other class' appendToResponse() method includes handling that cannot be * easily overridden, and assumes the content of the error map is essentially * a string-to-string map). As a result, there is a fair amount of * code duplication, but that can't be avoided without refactoring the * er.extensions version. * * @author Stephen Edwards * @version $Id: ErrorDictionaryPanel.java,v 1.1 2010/05/11 14:51:55 aallowat Exp $ */ public class ErrorDictionaryPanel extends er.extensions.components.ERXStatelessComponent { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Creates a new Footer object. * * @param context The page's context */ public ErrorDictionaryPanel( WOContext context ) { super( context ); } //~ KVC Attributes (must be public) ....................................... public String errorKey; // ---------------------------------------------------------- /** * A class to represent encoded error messages with category info * that . */ public static class ErrorMessage { // ---------------------------------------------------------- /** * Create a new error message object. * @param category The type of message--use the constants defined * in the {@link Status} class * @param message The content of the message * @param sticky True if this message should persist until it * it explicitly cleared; otherwise, it will be * cleared automatically after it has been displayed */ public ErrorMessage( byte category, String message, boolean sticky ) { this.category = category; this.message = message; this.sticky = sticky; } // ---------------------------------------------------------- /** * Retrieve this message's category. * @return this message's category */ public byte category() { return category; } // ---------------------------------------------------------- /** * Retrieve the string message associated with this object. * @return the message as a string */ public String message() { return message; } // ---------------------------------------------------------- /** * Determine whether this message is sticky. * @return true if this is a sticky message */ public boolean sticky() { return sticky; } // ---------------------------------------------------------- /** * Retrieve the string message associated with this object. No * category or sticky information is encoded in this * representation--only the object's string message is used. * @return the message as a string */ public String toString() { return message; } //~ Instance Fields ................................................... private byte category; private String message; private boolean sticky; } //~ Methods ............................................................... // ---------------------------------------------------------- @SuppressWarnings("unchecked") public NSMutableDictionary<String, ErrorMessage> errorMessages() { if ( errorMessages == null ) { errorMessages = (NSMutableDictionary<String, ErrorMessage>) valueForBinding( "errorMessages" ); if ( errorMessages == null ) { errorMessages = new NSMutableDictionary<String, ErrorMessage>(); } } return errorMessages; } // ---------------------------------------------------------- @SuppressWarnings("unchecked") public NSMutableArray<String> errorKeyOrder() { if ( errorKeyOrder == null ) { errorKeyOrder = (NSMutableArray<String>)valueForBinding( "errorKeyOrder" ); } return errorKeyOrder; } // ---------------------------------------------------------- public String extraErrorMessage() { if ( extraErrorMessage == null ) { extraErrorMessage = (String)valueForBinding( "extraErrorMessage" ); if ( extraErrorMessage != null ) { extraErrorMessage = massageErrorMessage( extraErrorMessage, null ); } } return extraErrorMessage; } // ---------------------------------------------------------- public boolean hasErrors() { return errorMessages().count() > 0 || ( extraErrorMessage() != null && extraErrorMessage().length() > 0 ); } // ---------------------------------------------------------- public NSArray<String> errorKeys() { return errorKeyOrder() != null ? errorKeyOrder() : errorMessages().allKeys(); } // ---------------------------------------------------------- public String errorMessageItem() { Object obj = errorMessages().objectForKey( errorKey ); String msg = ( obj instanceof Throwable ) ? ( (Throwable) obj).getMessage() : obj.toString(); return massageErrorMessage( msg, errorKey ); } // ---------------------------------------------------------- public byte errorMessageCategory( Object value ) { if ( value instanceof Throwable ) { return Status.ERROR; } else if ( value instanceof ErrorMessage ) { return ( (ErrorMessage)value ).category(); } else { return Status.WARNING; } } // ---------------------------------------------------------- public byte errorMessageCategory() { return errorMessageCategory( errorMessages().objectForKey( errorKey ) ); } // ---------------------------------------------------------- public String errorMessageCssClass() { return Status.statusCssClass( errorMessageCategory() ); } // ---------------------------------------------------------- public String dictionaryCssClass() { String style = ""; if ( extraErrorMessage() != null ) { style += " error"; // must include the space at start } else { NSDictionary<String, ErrorMessage> dict = errorMessages(); for ( Enumeration<String> e = dict.keyEnumerator(); e.hasMoreElements();) { byte category = errorMessageCategory( errorMessages().objectForKey( e.nextElement() ) ); switch ( category ) { case Status.ERROR: case Status.WARNING: case Status.UNFINISHED: style += " error"; // must include the space at start } } } if ( er.extensions.foundation.ERXValueUtilities.booleanValue( valueForBinding( "shouldShowNewlineAbove" ) ) ) { style += " nlbefore"; } if ( er.extensions.foundation.ERXValueUtilities.booleanValue( valueForBinding( "shouldShowNewlineBelow" ) ) ) { style += " nlafter"; } return style; } // ---------------------------------------------------------- public static String massageErrorMessage( String initialMessage, String displayErrorKey ) { String result = ERXExtensions.substituteStringByStringInString( "EOValidationException:", "", initialMessage ); if ( displayErrorKey != null ) { result = ERXExtensions.substituteStringByStringInString( ERXGenericRecord.KEY_MARKER, displayErrorKey, result ); } if ( result != null ) { if ( result.endsWith( "is not allowed to be null." ) || ( result.startsWith( " The " ) && result.indexOf( " property " ) != -1 && result.indexOf( " must have a " ) !=-1 && result.endsWith( " assigned" ) ) ) { char c; if ( displayErrorKey == null ) { result = result.substring( result.indexOf( "'" ) + 1, result.indexOf( "is not allowed to be null." ) - 2 ); c = result.charAt( 0 ); } else { result = displayErrorKey; c = result.toLowerCase().charAt( 0 ); } String article = ( c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') ? "an" : "a"; result = "Please provide " + article + " <b>" + result + "</b>."; } else if ( result.indexOf( ": Invalid number" ) != -1 ) { int colon = result.indexOf( ':' ); result = "<b>" + ( displayErrorKey == null ? result.substring( 0, colon - 1 ) : displayErrorKey ); result += "</b>: I could not understand the number you typed."; } else if ( result.indexOf( eliminable ) > 0 ) { result = result.substring( eliminable.length() + 1, result.length() ); } if ( result.indexOf( couldNotSave ) > 0 ) { String replace = ERXLocalizer.currentLocalizer() .localizedStringForKey( couldNotSave ); if ( replace != null ) { result = replace + result.substring( couldNotSave.length() + 1, result.length() ); } } } return result; } // ---------------------------------------------------------- public String panelClass() { if (panelClass == null) { byte category = Status.INFORMATION; for (String key : errorKeys()) { byte thisCategory = errorMessageCategory( errorMessages().objectForKey(key)); if (thisCategory < category) { category = thisCategory; } } panelClass = Status.statusCssClass(category); } return "NoticePanel " + panelClass; } // ---------------------------------------------------------- public void reset() { super.reset(); errorMessages = null; errorKeyOrder = null; extraErrorMessage = null; panelClass = null; } //~ Instance/static variables ............................................. protected NSMutableDictionary<String, ErrorMessage> errorMessages; protected NSMutableArray<String> errorKeyOrder; protected String extraErrorMessage; protected String panelClass; private final static String eliminable = "Could not save your changes: null"; private final static String couldNotSave = "Could not save your changes: "; }