You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2003/04/18 18:14:29 UTC

cvs commit: jakarta-tapestry/framework/src/org/apache/tapestry/spec IContainedComponent.java IListenerBindingSpecification.java

hlship      2003/04/18 09:14:28

  Modified:    examples/Vlib/context/WEB-INF EditUsers.page NewBook.page
                        EditProfile.page EditBook.page
               junit/src/org/apache/tapestry/junit/valid
                        TestStringValidator.java TestNumberValidator.java
                        TestDateValidator.java ValidSuite.java
               framework/src/org/apache/tapestry/valid EmailValidator.java
                        NumberValidator.java DateValidator.java
                        ValidationStrings.properties BaseValidator.java
                        StringValidator.java
                        ValidationStrings_de.properties
               web      new.html
               examples/Workbench/context/WEB-INF Chart.page
               framework/src/org/apache/tapestry/spec
                        IContainedComponent.java
                        IListenerBindingSpecification.java
  Added:       junit/src/org/apache/tapestry/junit/valid
                        TestEmailValidator.java
  Log:
  [ 19153 ] Easier way to override validation messages
  
  Revision  Changes    Path
  1.3       +5 -2      jakarta-tapestry/examples/Vlib/context/WEB-INF/EditUsers.page
  
  Index: EditUsers.page
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/context/WEB-INF/EditUsers.page,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- EditUsers.page	2 Apr 2003 19:22:38 -0000	1.2
  +++ EditUsers.page	18 Apr 2003 16:14:23 -0000	1.3
  @@ -12,6 +12,9 @@
     <property-specification name="listEditMap" type="org.apache.tapestry.vlib.pages.admin.UserListEditMap"/>
     <property-specification name="password" type="java.lang.String"/>
     
  +  <bean name="optional" class="org.apache.tapestry.valid.StringValidator" lifecycle="page"/>
  +
  +  
     <component id="e" type="ListEdit">
     	<binding name="source" expression="listEditMap.keys"/>
     	<binding name="value" expression="listEditMap.key"/>
  @@ -21,7 +24,7 @@
     
     <component id="inputPassword" type="ValidField">
       <binding name="value" expression="password"/>
  -    <binding name="validator" expression="@org.apache.tapestry.valid.StringValidator@OPTIONAL"/>
  +    <binding name="validator" expression="beans.optional"/>
       <static-binding name="displayName" value="New Password"/>	
     </component>
   
  
  
  
  1.8       +4 -2      jakarta-tapestry/examples/Vlib/context/WEB-INF/NewBook.page
  
  Index: NewBook.page
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/context/WEB-INF/NewBook.page,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- NewBook.page	29 Mar 2003 18:49:07 -0000	1.7
  +++ NewBook.page	18 Apr 2003 16:14:24 -0000	1.8
  @@ -14,6 +14,8 @@
       <set-property name="required" expression="true"/>
       <set-property name="clientScriptingEnabled" expression="true"/>
     </bean>
  +  
  +  <bean name="optional" class="org.apache.tapestry.valid.StringValidator" lifecycle="page"/>
       
     <component id="inputTitle" type="ValidField">
       <binding name="value" expression="attributes.title"/>
  @@ -30,7 +32,7 @@
     
     <component id="inputPublisherName" type="ValidField">
       <binding name="value" expression="publisherName"/>
  -    <binding name="validator" expression="@org.apache.tapestry.valid.StringValidator@OPTIONAL"/>
  +    <binding name="validator" expression="beans.optional"/>
       <static-binding name="displayName" value="Publisher"/>
     </component>
       
  
  
  
  1.7       +8 -6      jakarta-tapestry/examples/Vlib/context/WEB-INF/EditProfile.page
  
  Index: EditProfile.page
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/context/WEB-INF/EditProfile.page,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- EditProfile.page	29 Mar 2003 18:49:07 -0000	1.6
  +++ EditProfile.page	18 Apr 2003 16:14:24 -0000	1.7
  @@ -11,34 +11,36 @@
     <property-specification name="password2" type="java.lang.String"/>
     <property-specification name="attributes" type="java.util.Map"/>
    
  -  <bean name="validator" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
  +  <bean name="required" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
     	<set-property name="required" expression="true"/>
     	<set-property name="clientScriptingEnabled" expression="true"/>
     </bean>
  +  
  +  <bean name="optional" class="org.apache.tapestry.valid.StringValidator" lifecycle="page"/>
   
     <component id="inputLastName" type="ValidField">
       <binding name="value" expression="attributes.lastName"/>
       <static-binding name="displayName" value="Last Name"/>   
  -    <binding name="validator" expression="beans.validator"/>
  +    <binding name="validator" expression="beans.required"/>
     </component>
   
     <component id="inputEmail" type="ValidField">
       <binding name="value" expression="attributes.email"/>
       <static-binding name="displayName" value="E-Mail"/>
  -    <binding name="validator" expression="beans.validator"/>
  +    <binding name="validator" expression="beans.required"/>
     </component>
   
     <component id="inputPassword1" type="ValidField">
       <binding name="value" expression="password1"/>
       <static-binding name="displayName" value="Password"/> 
  -    <binding name="validator" expression="@org.apache.tapestry.valid.StringValidator@OPTIONAL"/>
  +    <binding name="validator" expression="beans.optional"/>
       <binding name="hidden" expression="true"/>
     </component>
   
     <component id="inputPassword2" type="ValidField">
       <binding name="value" expression="password2"/>
       <static-binding name="displayName" value="Password (again)"/>  
  -    <binding name="validator" expression="@org.apache.tapestry.valid.StringValidator@OPTIONAL"/>
  +    <binding name="validator" expression="beans.optional"/>
       <binding name="hidden" expression="true"/>
     </component>
     
  
  
  
  1.9       +9 -5      jakarta-tapestry/examples/Vlib/context/WEB-INF/EditBook.page
  
  Index: EditBook.page
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Vlib/context/WEB-INF/EditBook.page,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- EditBook.page	10 Apr 2003 21:02:28 -0000	1.8
  +++ EditBook.page	18 Apr 2003 16:14:24 -0000	1.9
  @@ -13,21 +13,25 @@
     <property-specification name="bookId" type="java.lang.Integer"/>
     <property-specification name="publisherName" type="java.lang.String"/>
     
  -  <bean name="validator" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
  +  <bean name="required" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
     	<set-property name="required" expression="true"/>
     	<set-property name="clientScriptingEnabled" expression="true"/>
     </bean>
     
  +	<bean name="optional" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
  +	  <set-property name="required" expression="true"/>
  +	</bean>
  +  
     <component id="inputTitle" type="ValidField">
       <binding name="value" expression="attributes.title"/>
       <static-binding name="displayName" value="Title"/>
  -    <binding name="validator" expression="beans.validator"/>
  +    <binding name="validator" expression="beans.required"/>
     </component>
    
     <component id="inputAuthor" type="ValidField">
       <binding name="value" expression="attributes.author"/>
       <static-binding name="displayName" value="Author"/>
  -    <binding name="validator" expression="beans.validator"/>
  +    <binding name="validator" expression="beans.required"/>
     </component>
     
     <component id="inputPublisher" type="PropertySelection">
  @@ -38,7 +42,7 @@
     <component id="inputPublisherName" type="ValidField">
       <binding name="value" expression="publisherName"/>
       <static-binding name="displayName" value="Publisher"/>
  -    <binding name="validator" expression="@org.apache.tapestry.valid.StringValidator@OPTIONAL"/>
  +    <binding name="validator" expression="beans.optional"/>
     </component>
   
   
  
  
  
  1.3       +39 -58    jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestStringValidator.java
  
  Index: TestStringValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestStringValidator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestStringValidator.java	15 Mar 2003 21:22:26 -0000	1.2
  +++ TestStringValidator.java	18 Apr 2003 16:14:24 -0000	1.3
  @@ -105,10 +105,26 @@
           }
           catch (ValidatorException ex)
           {
  +            assertEquals("You must enter a value for requiredField.", ex.getMessage());
               assertEquals(ValidationConstraint.REQUIRED, ex.getConstraint());
           }
       }
   
  +    public void testOverrideRequiredMessage()
  +    {
  +        v.setRequired(true);
  +        v.setRequiredMessage("Gimme a value for {0} you bastard.");
  +
  +        try
  +        {
  +            v.toObject(new TestingField("overrideMessage"), "");
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals("Gimme a value for overrideMessage you bastard.", ex.getMessage());
  +        }
  +    }
  +
       public void testToObjectRequiredPass() throws ValidatorException
       {
           v.setRequired(true);
  @@ -124,16 +140,37 @@
   
           try
           {
  -            v.toObject(new TestingField("minimum"), "short");
  +            v.toObject(new TestingField("minimumLength"), "short");
   
               fail("Exception expected.");
           }
           catch (ValidatorException ex)
           {
  +            assertEquals(
  +                "You must enter at least 10 characters for minimumLength.",
  +                ex.getMessage());
               assertEquals(ValidationConstraint.MINIMUM_WIDTH, ex.getConstraint());
           }
       }
   
  +    public void testOverrideMinimumMessage()
  +    {
  +        v.setMinimumLength(10);
  +        v.setMinimumLengthMessage(
  +            "You really think less than 10 characters for {0} is gonna cut it?");
  +
  +        try
  +        {
  +            v.toObject(new TestingField("overrideMessage"), "");
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals(
  +                "You really think less than 10 characters for overrideMessage is gonna cut it?",
  +                ex.getMessage());
  +        }
  +    }
  +
       public void testToObjectMinimumPass() throws ValidatorException
       {
           v.setMinimumLength(10);
  @@ -159,62 +196,6 @@
           Object out = v.toObject(new TestingField("minimum"), in);
   
           assertNull("Result", out);
  -    }
  -
  -    public void testOptional()
  -    {
  -        assertEquals(0, StringValidator.OPTIONAL.getMinimumLength());
  -        assertEquals(false, StringValidator.OPTIONAL.isClientScriptingEnabled());
  -        assertEquals(false, StringValidator.OPTIONAL.isRequired());
  -    }
  -
  -    public void testRequired()
  -    {
  -        assertEquals(0, StringValidator.REQUIRED.getMinimumLength());
  -        assertEquals(false, StringValidator.REQUIRED.isClientScriptingEnabled());
  -        assertEquals(true, StringValidator.REQUIRED.isRequired());
  -    }
  -
  -    public void testSetStaticMinimumLength()
  -    {
  -        try
  -        {
  -            StringValidator.OPTIONAL.setMinimumLength(1);
  -
  -            unreachable();
  -        }
  -        catch (UnsupportedOperationException ex)
  -        {
  -            checkException(ex, "Changes to property values are not allowed.");
  -        }
  -    }
  -
  -    public void testSetStaticClientScripting()
  -    {
  -        try
  -        {
  -            StringValidator.OPTIONAL.setClientScriptingEnabled(true);
  -
  -            unreachable();
  -        }
  -        catch (UnsupportedOperationException ex)
  -        {
  -            checkException(ex, "Changes to property values are not allowed.");
  -        }
  -    }
  -
  -    public void testSetRequired()
  -    {
  -        try
  -        {
  -            StringValidator.OPTIONAL.setRequired(true);
  -
  -            unreachable();
  -        }
  -        catch (UnsupportedOperationException ex)
  -        {
  -            checkException(ex, "Changes to property values are not allowed.");
  -        }
       }
   
   }
  
  
  
  1.2       +77 -4     jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestNumberValidator.java
  
  Index: TestNumberValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestNumberValidator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestNumberValidator.java	5 Mar 2003 23:19:55 -0000	1.1
  +++ TestNumberValidator.java	18 Apr 2003 16:14:24 -0000	1.2
  @@ -61,6 +61,7 @@
   import org.apache.tapestry.form.IFormComponent;
   import org.apache.tapestry.junit.TapestryTestCase;
   import org.apache.tapestry.valid.NumberValidator;
  +import org.apache.tapestry.valid.ValidationConstraint;
   import org.apache.tapestry.valid.ValidatorException;
   
   /**
  @@ -150,7 +151,24 @@
           }
           catch (ValidatorException ex)
           {
  -            checkException(ex, "testUnderMinimum must not be smaller than 100.");
  +            assertEquals("testUnderMinimum must not be smaller than 100.", ex.getMessage());
  +            assertEquals(ValidationConstraint.TOO_SMALL, ex.getConstraint());
  +        }
  +    }
  +
  +    public void testOverrideNumberTooSmallMessage()
  +    {
  +        v.setMinimum(new Integer(100));
  +        v.setNumberTooSmallMessage("Anything under 100 for {0} is worth jack.");
  +
  +        try
  +        {
  +            testPassThru("underMinimum", Integer.class, new Integer(50));
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals("Anything under 100 for underMinimum is worth jack.", ex.getMessage());
           }
       }
   
  @@ -161,13 +179,68 @@
   
           try
           {
  -            testPassThru("testUnderMinimum", Integer.class, new Integer(250));
  +            testPassThru("overMaximum", Integer.class, new Integer(250));
   
               unreachable();
           }
           catch (ValidatorException ex)
           {
  -            checkException(ex, "testUnderMinimum must not be larger than 200.");
  +            assertEquals("overMaximum must not be larger than 200.", ex.getMessage());
  +            assertEquals(ValidationConstraint.TOO_LARGE, ex.getConstraint());
  +        }
  +    }
  +
  +    public void testOverrideNumberTooLargeMessage()
  +    {
  +        v.setMaximum(new Integer(200));
  +        v.setNumberTooLargeMessage("You think I want a value larger than {1} for {0}?");
  +
  +        try
  +        {
  +            testPassThru("overMaximum", Integer.class, new Integer(1000));
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals(
  +                "You think I want a value larger than 200 for overMaximum?",
  +                ex.getMessage());
  +        }
  +    }
  +
  +    public void testInvalidFormat()
  +    {
  +        v.setValueTypeClass(Integer.class);
  +        IFormComponent field = new TestingField("invalidFormat");
  +
  +        try
  +        {
  +            v.toObject(field, "xyz");
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals("invalidFormat must be a numeric value.", ex.getMessage());
  +            assertEquals(ValidationConstraint.NUMBER_FORMAT, ex.getConstraint());
  +        }
  +    }
  +
  +    public void testOverrideInvalidNumericFormatMessage()
  +    {
  +        v.setValueTypeClass(Integer.class);
  +        v.setInvalidNumericFormatMessage("Dude, gimme a number for {0}.");
  +
  +        IFormComponent field = new TestingField("invalidFormat");
  +
  +        try
  +        {
  +            v.toObject(field, "xyz");
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals("Dude, gimme a number for invalidFormat.", ex.getMessage());
  +            assertEquals(ValidationConstraint.NUMBER_FORMAT, ex.getConstraint());
           }
       }
   
  
  
  
  1.2       +61 -5     jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestDateValidator.java
  
  Index: TestDateValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestDateValidator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestDateValidator.java	5 Mar 2003 23:19:55 -0000	1.1
  +++ TestDateValidator.java	18 Apr 2003 16:14:25 -0000	1.2
  @@ -144,16 +144,36 @@
       {
           try
           {
  -            v.toObject(new TestingField("toObjectInvalid"), "frankenhooker");
  +            v.toObject(new TestingField("badDatesIndy"), "frankenhooker");
   
  -            fail("Exception expected.");
  +            unreachable();
           }
           catch (ValidatorException ex)
           {
  +            assertEquals(
  +                "Invalid date format for badDatesIndy.  Format is MM/DD/YYYY.",
  +                ex.getMessage());
               assertEquals(ValidationConstraint.DATE_FORMAT, ex.getConstraint());
           }
       }
   
  +    public void testOverrideInvalidDateFormatMessage()
  +    {
  +        v.setInvalidDateFormatMessage("Enter a valid date for {0}.");
  +
  +        try
  +        {
  +            v.toObject(new TestingField("badDatesIndy"), "frankenhooker");
  +
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals("Enter a valid date for badDatesIndy.", ex.getMessage());
  +
  +        }
  +    }
  +
       public void testToObjectFormat() throws ValidatorException
       {
           if (IS_JDK13)
  @@ -185,6 +205,23 @@
           }
       }
   
  +    public void testOverrideDateTooEarlyMessage()
  +    {
  +        v.setMinimum(buildDate(Calendar.DECEMBER, 24, 2001));
  +        v.setDateTooEarlyMessage("Provide a date for {0} after Dec 24 2001.");
  +
  +        try
  +        {
  +            v.toObject(new TestingField("inputDate"), "12/8/2001");
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals("Provide a date for inputDate after Dec 24 2001.", ex.getMessage());
  +            assertEquals(ValidationConstraint.TOO_SMALL, ex.getConstraint());
  +        }
  +    }
  +
       public void testToObjectMinimumNull() throws ValidatorException
       {
           v.setMinimum(buildDate(Calendar.DECEMBER, 24, 2001));
  @@ -200,12 +237,31 @@
   
           try
           {
  -            v.toObject(new TestingField("toObjectMinimum"), "12/8/2002");
  -            fail("Exception expected.");
  +            v.toObject(new TestingField("toObjectMaximum"), "12/8/2002");
  +            unreachable();
           }
           catch (ValidatorException ex)
           {
  +            assertEquals("toObjectMaximum must be on or before 12/24/2001.", ex.getMessage());
               assertEquals(ValidationConstraint.TOO_LARGE, ex.getConstraint());
  +        }
  +    }
  +
  +    public void testOverrideDateTooLateMessage()
  +    {
  +        v.setMaximum(buildDate(Calendar.DECEMBER, 24, 2001));
  +        v.setDateTooLateMessage("Try again with a date before Dec 24 2001 in {0}.");
  +
  +        try
  +        {
  +            v.toObject(new TestingField("toObjectMaximum"), "12/8/2002");
  +            unreachable();
  +        }
  +        catch (ValidatorException ex)
  +        {
  +            assertEquals(
  +                "Try again with a date before Dec 24 2001 in toObjectMaximum.",
  +                ex.getMessage());
           }
       }
   
  
  
  
  1.2       +2 -1      jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/ValidSuite.java
  
  Index: ValidSuite.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/ValidSuite.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ValidSuite.java	5 Mar 2003 23:19:55 -0000	1.1
  +++ ValidSuite.java	18 Apr 2003 16:14:25 -0000	1.2
  @@ -79,6 +79,7 @@
           suite.addTest(new TestSuite(TestDateValidator.class));
           suite.addTest(new TestSuite(TestNumberValidator.class));
           suite.addTest(new TestSuite(TestValidationDelegate.class));
  +        suite.addTest(new TestSuite(TestEmailValidator.class));
   
           return suite;
   
  
  
  
  1.1                  jakarta-tapestry/junit/src/org/apache/tapestry/junit/valid/TestEmailValidator.java
  
  Index: TestEmailValidator.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation", "Tapestry" 
   *    must not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache" 
   *    or "Tapestry", nor may "Apache" or "Tapestry" appear in their 
   *    name, without prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE TAPESTRY CONTRIBUTOR COMMUNITY
   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.tapestry.junit.valid;
  
  import org.apache.tapestry.junit.TapestryTestCase;
  import org.apache.tapestry.valid.EmailValidator;
  import org.apache.tapestry.valid.ValidationConstraint;
  import org.apache.tapestry.valid.ValidatorException;
  
  /**
   * Tests for {@link org.apache.tapestry.valid.EmailValidator}.
   *
   * @author Howard Lewis Ship
   * @version $Id: TestEmailValidator.java,v 1.1 2003/04/18 16:14:25 hlship Exp $
   * @since 3.0
   *
   **/
  
  public class TestEmailValidator extends TapestryTestCase
  {
      private EmailValidator v = new EmailValidator();
  
      public TestEmailValidator(String name)
      {
          super(name);
      }
  
      public void testValidEmail() throws ValidatorException
      {
          Object result = v.toObject(new TestingField("email"), "foo@bar.com");
          assertEquals("foo@bar.com", result);
      }
  
      public void testInvalidEmail()
      {
          try
          {
              v.toObject(new TestingField("email"), "fred");
              unreachable();
          }
          catch (ValidatorException ex)
          {
              assertEquals(ValidationConstraint.EMAIL_FORMAT, ex.getConstraint());
              assertEquals(
                  "Invalid email format for email.  Format is user@hostname.",
                  ex.getMessage());
          }
      }
  
      public void testOverrideInvalidEmailFormatMessage()
      {
          v.setInvalidEmailFormatMessage(
              "Try a valid e-mail address (for {0}), like ''dick@wad.com.''");
  
          try
          {
              v.toObject(new TestingField("email"), "fred");
              unreachable();
          }
          catch (ValidatorException ex)
          {
              assertEquals(
                  "Try a valid e-mail address (for email), like 'dick@wad.com.'",
                  ex.getMessage());
          }
      }
  
      public void testTooShort()
      {
          v.setMinimumLength(20);
  
          try
          {
              v.toObject(new TestingField("short"), "foo@bar.com");
              unreachable();
          }
          catch (ValidatorException ex)
          {
              assertEquals(ValidationConstraint.MINIMUM_WIDTH, ex.getConstraint());
              assertEquals("You must enter at least 20 characters for short.", ex.getMessage());
          }
      }
  
      public void testOverrideMinimumLengthMessage()
      {
          v.setMinimumLength(20);
          v.setMinimumLengthMessage("E-mail addresses must be at least 20 characters.");
  
          try
          {
              v.toObject(new TestingField("short"), "foo@bar.com");
              unreachable();
          }
          catch (ValidatorException ex)
          {
              assertEquals("E-mail addresses must be at least 20 characters.", ex.getMessage());
          }
      }
  }
  
  
  
  1.3       +80 -33    jakarta-tapestry/framework/src/org/apache/tapestry/valid/EmailValidator.java
  
  Index: EmailValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/EmailValidator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- EmailValidator.java	15 Mar 2003 21:22:22 -0000	1.2
  +++ EmailValidator.java	18 Apr 2003 16:14:25 -0000	1.3
  @@ -78,6 +78,8 @@
   public class EmailValidator extends BaseValidator
   {
       private int _minimumLength;
  +    private String _minimumLengthMessage;
  +    private String _invalidEmailFormatMessage;
   
       private String _scriptPath = "/org/apache/tapestry/valid/EmailValidator.script";
   
  @@ -103,30 +105,15 @@
           if (checkRequired(field, input))
               return null;
   
  -        input = input.trim();
  -
           if (_minimumLength > 0 && input.length() < _minimumLength)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "field-too-short",
  -                    field.getPage().getLocale(),
  -                    Integer.toString(_minimumLength),
  -                    field.getDisplayName());
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.MINIMUM_WIDTH);
  -        }
  -
  -        if (input.length() > 0 && !isValidEmail(input))
  -        {
  -            String errorMessage =
  -                getString(
  -                    "invalid-email-format",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName());
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.EMAIL_FORMAT);
  -        }
  +            throw new ValidatorException(
  +                buildMinimumLengthMessage(field),
  +                ValidationConstraint.MINIMUM_WIDTH);
  +
  +        if (!isValidEmail(input))
  +            throw new ValidatorException(
  +                buildInvalidEmailFormatMessage(field),
  +                ValidationConstraint.EMAIL_FORMAT);
   
           return input;
       }
  @@ -155,18 +142,14 @@
           String displayName = field.getDisplayName();
   
           if (isRequired())
  -            symbols.put("requiredMessage", getString("field-is-required", locale, displayName));
  +            symbols.put("requiredMessage", buildRequiredMessage(field));
   
           if (_minimumLength > 0)
  -            symbols.put(
  -                "minimumLengthMessage",
  -                getString(
  -                    "field-too-short",
  -                    locale,
  -                    Integer.toString(_minimumLength),
  -                    displayName));
  +            symbols.put("minimumLengthMessage", buildMinimumLengthMessage(field));
  +
  +        String pattern = getPattern(getInvalidEmailFormatMessage(), "invalid-email-format", locale);
   
  -        symbols.put("emailFormatMessage", getString("invalid-email-format", locale, displayName));
  +        symbols.put("emailFormatMessage", formatString(pattern, displayName));
   
           processValidatorScript(_scriptPath, cycle, field, symbols);
       }
  @@ -208,5 +191,69 @@
           {
               return true;
           }
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getInvalidEmailFormatMessage()
  +    {
  +        return _invalidEmailFormatMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getMinimumLengthMessage()
  +    {
  +        return _minimumLengthMessage;
  +    }
  +
  +    /**
  +     *  Overrides the <code>invalid-email-format</code>
  +     *  bundle key.
  +     *  Parameter {0} is the display name of the field.
  +     * 
  +     *  @since 3.0
  +     * 
  +     */
  +
  +    public void setInvalidEmailFormatMessage(String string)
  +    {
  +        _invalidEmailFormatMessage = string;
  +    }
  +
  +    /**
  +     *  Overrides the <code>field-too-short</code> bundle key.
  +     *  Parameter {0} is the minimum length.
  +     *  Parameter {1} is the display name of the field.
  +     * 
  +     *  @since 3.0
  +     * 
  +     */
  +    public void setMinimumLengthMessage(String string)
  +    {
  +        _minimumLengthMessage = string;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildMinimumLengthMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(_minimumLengthMessage, "field-too-short", field.getPage().getLocale());
  +
  +        return formatString(pattern, Integer.toString(_minimumLength), field.getDisplayName());
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildInvalidEmailFormatMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(
  +                _invalidEmailFormatMessage,
  +                "invalid-email-format",
  +                field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName());
       }
   }
  
  
  
  1.4       +145 -44   jakarta-tapestry/framework/src/org/apache/tapestry/valid/NumberValidator.java
  
  Index: NumberValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/NumberValidator.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- NumberValidator.java	17 Apr 2003 21:33:58 -0000	1.3
  +++ NumberValidator.java	18 Apr 2003 16:14:26 -0000	1.4
  @@ -119,6 +119,11 @@
   
       private String _scriptPath = "/org/apache/tapestry/valid/NumberValidator.script";
   
  +    private String _invalidNumericFormatMessage;
  +    private String _numberTooSmallMessage;
  +    private String _numberTooLargeMessage;
  +    private String _numberRangeMessage;
  +
       private static AdaptorRegistry _numberAdaptors = new AdaptorRegistry();
   
       private static abstract class NumberAdaptor
  @@ -273,38 +278,20 @@
           }
           catch (NumberFormatException ex)
           {
  -            String errorMessage =
  -                getString(
  -                    "invalid-numeric-format",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName());
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.NUMBER_FORMAT);
  +            throw new ValidatorException(
  +                buildInvalidNumericFormatMessage(field),
  +                ValidationConstraint.NUMBER_FORMAT);
           }
   
           if (_minimum != null && adaptor.compare(result, _minimum) < 0)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "number-too-small",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName(),
  -                    _minimum);
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.TOO_SMALL);
  -        }
  +            throw new ValidatorException(
  +                buildNumberTooSmallMessage(field),
  +                ValidationConstraint.TOO_SMALL);
   
           if (_maximum != null && adaptor.compare(result, _maximum) > 0)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "number-too-large",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName(),
  -                    _maximum);
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.TOO_LARGE);
  -        }
  +            throw new ValidatorException(
  +                buildNumberTooLargeMessage(field),
  +                ValidationConstraint.TOO_LARGE);
   
           return result;
       }
  @@ -374,34 +361,26 @@
   
           Map symbols = new HashMap();
   
  -        Locale locale = field.getPage().getLocale();
  -        String displayName = field.getDisplayName();
  -
           if (isRequired())
  -            symbols.put("requiredMessage", getString("field-is-required", locale, displayName));
  +            symbols.put("requiredMessage", buildRequiredMessage(field));
   
  -        symbols.put("formatMessage", getString("invalid-numeric-format", locale, displayName));
  +        symbols.put("formatMessage", buildInvalidNumericFormatMessage(field));
   
           if (_minimum != null || _maximum != null)
  -        {
  -            symbols.put("rangeMessage", buildRangeMessage(displayName, locale));
  -        }
  +            symbols.put("rangeMessage", buildRangeMessage(field));
   
           processValidatorScript(_scriptPath, cycle, field, symbols);
       }
   
  -    private String buildRangeMessage(String displayName, Locale locale)
  +    private String buildRangeMessage(IFormComponent field)
       {
           if (_minimum != null && _maximum != null)
  -            return getString(
  -                "number-range",
  -                locale,
  -                new Object[] { displayName, _minimum, _maximum });
  +            return buildNumberRangeMessage(field);
   
  -        if (_minimum != null)
  -            return getString("number-too-small", locale, displayName, _minimum);
  +        if (_maximum != null)
  +            return buildNumberTooLargeMessage(field);
   
  -        return getString("number-too-large", locale, displayName, _maximum);
  +        return buildNumberTooSmallMessage(field);
       }
   
       /**
  @@ -466,6 +445,128 @@
       public Class getValueTypeClass()
       {
           return _valueTypeClass;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getInvalidNumericFormatMessage()
  +    {
  +        return _invalidNumericFormatMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getNumberRangeMessage()
  +    {
  +        return _numberRangeMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getNumberTooLargeMessage()
  +    {
  +        return _numberTooLargeMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getNumberTooSmallMessage()
  +    {
  +        return _numberTooSmallMessage;
  +    }
  +
  +    /** 
  +     * Overrides the <code>invalid-numeric-format</code> bundle key.
  +     * Parameter {0} is the display name of the field.
  +     * 
  +     * @since 3.0
  +     */
  +
  +    public void setInvalidNumericFormatMessage(String string)
  +    {
  +        _invalidNumericFormatMessage = string;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildInvalidNumericFormatMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(
  +                getInvalidNumericFormatMessage(),
  +                "invalid-numeric-format",
  +                field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName());
  +    }
  +
  +    /** 
  +     * Overrides the <code>number-range</code> bundle key.
  +     * Parameter [0} is the display name of the field.
  +     * Parameter {1} is the minimum value.
  +     * Parameter {2} is the maximum value.
  +     * 
  +     * @since 3.0
  +     */
  +
  +    public void setNumberRangeMessage(String string)
  +    {
  +        _numberRangeMessage = string;
  +    }
  +
  +    protected String buildNumberRangeMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(_numberRangeMessage, "number-range", field.getPage().getLocale());
  +
  +        return formatString(pattern, new Object[] { field.getDisplayName(), _minimum, _maximum });
  +    }
  +
  +    /**
  +     *  Overrides the <code>number-too-large</code> bundle key.
  +     *  Parameter {0} is the display name of the field.
  +     *  Parameter {1} is the maximum allowed value.
  +     *  
  +     *  @since 3.0
  +     */
  +
  +    public void setNumberTooLargeMessage(String string)
  +    {
  +        _numberTooLargeMessage = string;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildNumberTooLargeMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(_numberTooLargeMessage, "number-too-large", field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName(), _maximum);
  +    }
  +
  +    /**
  +     *  Overrides the <code>number-too-small</code> bundle key.
  +     *  Parameter {0} is the display name of the field.
  +     *  Parameter {1} is the minimum allowed value.
  +     * 
  +     *  @since 3.0
  +     * 
  +     */
  +
  +    public void setNumberTooSmallMessage(String string)
  +    {
  +        _numberTooSmallMessage = string;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildNumberTooSmallMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(_numberTooSmallMessage, "number-too-small", field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName(), _minimum);
       }
   
   }
  
  
  
  1.3       +112 -36   jakarta-tapestry/framework/src/org/apache/tapestry/valid/DateValidator.java
  
  Index: DateValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/DateValidator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- DateValidator.java	15 Mar 2003 21:22:22 -0000	1.2
  +++ DateValidator.java	18 Apr 2003 16:14:26 -0000	1.3
  @@ -89,7 +89,11 @@
       private String _scriptPath = "/org/apache/tapestry/valid/DateValidator.script";
   
       private static DateFormat defaultDateFormat = new SimpleDateFormat("MM/dd/yyyy");
  -    private static String defaultDateDisplayFormat = "MM/DD/YYYY";
  +    private static final String defaultDateDisplayFormat = "MM/DD/YYYY";
  +
  +    private String _dateTooEarlyMessage;
  +    private String _dateTooLateMessage;
  +    private String _invalidDateFormatMessage;
   
       public void setFormat(DateFormat value)
       {
  @@ -185,42 +189,21 @@
           }
   
           if (result == null)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "invalid-date-format",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName(),
  -                    getEffectiveDisplayFormat());
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.DATE_FORMAT);
  -        }
  +            throw new ValidatorException(
  +                buildInvalidDateFormatMessage(field),
  +                ValidationConstraint.DATE_FORMAT);
   
           // OK, check that the date is in range.
   
           if (_minimum != null && _minimum.compareTo(result) > 0)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "date-too-early",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName(),
  -                    format.format(_minimum));
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.TOO_SMALL);
  -        }
  +            throw new ValidatorException(
  +                buildDateTooEarlyMessage(field, format.format(_minimum)),
  +                ValidationConstraint.TOO_SMALL);
   
           if (_maximum != null && _maximum.compareTo(result) < 0)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "date-too-late",
  -                    field.getPage().getLocale(),
  -                    field.getDisplayName(),
  -                    format.format(_maximum));
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.TOO_LARGE);
  -        }
  +            throw new ValidatorException(
  +                buildDateTooLateMessage(field, format.format(_maximum)),
  +                ValidationConstraint.TOO_LARGE);
   
           return result;
   
  @@ -262,10 +245,7 @@
   
           Map symbols = new HashMap();
   
  -        Locale locale = field.getPage().getLocale();
  -        String displayName = field.getDisplayName();
  -
  -        symbols.put("requiredMessage", getString("field-is-required", locale, displayName));
  +        symbols.put("requiredMessage", buildRequiredMessage(field));
   
           processValidatorScript(_scriptPath, cycle, field, symbols);
       }
  @@ -293,6 +273,102 @@
       public void setScriptPath(String scriptPath)
       {
           _scriptPath = scriptPath;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getDateTooEarlyMessage()
  +    {
  +        return _dateTooEarlyMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getDateTooLateMessage()
  +    {
  +        return _dateTooLateMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    public String getInvalidDateFormatMessage()
  +    {
  +        return _invalidDateFormatMessage;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildInvalidDateFormatMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(
  +                _invalidDateFormatMessage,
  +                "invalid-date-format",
  +                field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName(), getEffectiveDisplayFormat());
  +    }
  +
  +    /** @since 3.0 **/
  +
  +    protected String buildDateTooEarlyMessage(IFormComponent field, String earliestDate)
  +    {
  +        String pattern =
  +            getPattern(_dateTooEarlyMessage, "date-too-early", field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName(), earliestDate);
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildDateTooLateMessage(IFormComponent field, String latestDate)
  +    {
  +        String pattern =
  +            getPattern(_dateTooLateMessage, "date-too-late", field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName(), latestDate);
  +    }
  +
  +    /**
  +     *  Overrides the bundle key
  +     *  <code>date-too-early</code>.
  +     *  Parameter {0} is the display name of the field.
  +     *  Parameter {1} is the earliest allowed date.
  +     * 
  +     *  @since 3.0
  +     */
  +
  +    public void setDateTooEarlyMessage(String string)
  +    {
  +        _dateTooEarlyMessage = string;
  +    }
  +
  +    /**
  +     *  Overrides the bundle key
  +     *  <code>date-too-late</code>.
  +     *  Parameter {0} is the display name of the field.
  +     *  Parameter {1} is the latest allowed date.
  +     * 
  +     *  @since 3.0
  +     */
  +
  +    public void setDateTooLateMessage(String string)
  +    {
  +        _dateTooLateMessage = string;
  +    }
  +
  +    /**
  +     *  Overrides the bundle key
  +     *  <code>invalid-date-format</code>.
  +     *  Parameter {0} is the display name of the field.
  +     *  Parameter {1} is the allowed format.
  +     * 
  +     *  @since 3.0
  +     */
  +
  +    public void setInvalidDateFormatMessage(String string)
  +    {
  +        _invalidDateFormatMessage = string;
       }
   
   }
  
  
  
  1.2       +2 -2      jakarta-tapestry/framework/src/org/apache/tapestry/valid/ValidationStrings.properties
  
  Index: ValidationStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/ValidationStrings.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ValidationStrings.properties	5 Mar 2003 22:59:40 -0000	1.1
  +++ ValidationStrings.properties	18 Apr 2003 16:14:26 -0000	1.2
  @@ -16,4 +16,4 @@
   
   number-range={0} must be between {1} and {2}.
   
  -invalid-email-format=Invalid email format for {0}.  Format is user@hostname
  \ No newline at end of file
  +invalid-email-format=Invalid email format for {0}.  Format is user@hostname.
  \ No newline at end of file
  
  
  
  1.3       +83 -25    jakarta-tapestry/framework/src/org/apache/tapestry/valid/BaseValidator.java
  
  Index: BaseValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/BaseValidator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- BaseValidator.java	15 Mar 2003 21:22:22 -0000	1.2
  +++ BaseValidator.java	18 Apr 2003 16:14:26 -0000	1.3
  @@ -138,6 +138,10 @@
   
       private boolean _required;
   
  +    /** @since 3.0 */
  +
  +    private String _requiredMessage;
  +
       /** 
        *  @since 2.2
        * 
  @@ -170,52 +174,74 @@
       }
   
       /**
  -     *  Gets a string from the standard resource bundle.  The string in the bundle
  -     *  is treated as a pattern for {@link MessageFormat#format(java.lang.String, java.lang.Object[])}.
  -     * 
  -     *  <p>Why do we not just lump these strings into TapestryStrings.properties?  
  -     *  Because TapestryStrings.properties is localized to the server's locale, which is fine
  -     *  for the logging, debugging and error messages it contains.  For field validation, whose errors
  -     *  are visible to the end user normally, we want to localize to the page and engine's locale.
  -     * 
  -     *  <p>This will be more useful when we have actual localizations of ValidationStrings.properties.
  -     * 
  -     *  @since 2.1
  -     * 
  -     **/
  +     * Gets a pattern, either as the default value, or as a localized key.
  +     * If override is null, then the key from the
  +     * <code>org.apache.tapestry.valid.ValidationStrings</code>
  +     * {@link ResourceBundle} (in the specified locale) is used.
  +     * The pattern can then be used with {@link #formatString(String, Object[])}.
  +     * 
  +     * <p>Why do we not just lump these strings into TapestryStrings.properties?  
  +     * because TapestryStrings.properties is localized to the server's locale, which is fine
  +     * for the logging, debugging and error messages it contains.  For field validation, whose errors
  +     * are visible to the end user normally, we want to localize to the page's locale.
  +     *  
  +     * @param override The override value for the localized string from the bundle.
  +     * @param key used to lookup pattern from bundle, if override is null.
  +     * @param locale used to get right localization of bundle.
  +     * @since 3.0
  +     */
   
  -    protected String getString(String key, Locale locale, Object[] args)
  +    protected String getPattern(String override, String key, Locale locale)
       {
  +        if (override != null)
  +            return override;
  +
           ResourceBundle strings =
               ResourceBundle.getBundle("org.apache.tapestry.valid.ValidationStrings", locale);
   
  -        String pattern = strings.getString(key);
  +        return strings.getString(key);
  +    }
  +
  +    /**
  +     * Gets a string from the standard resource bundle.  The string in the bundle
  +     * is treated as a pattern for {@link MessageFormat#format(java.lang.String, java.lang.Object[])}.
  +     * 
  +     * @param localized string the input pattern to be used with 
  +     * {@link MessageFormat#format(java.lang.String, java.lang.Object[])}.
  +     * It may contain replaceable parameters, {0}, {1}, etc.
  +     * @param args the arguments used to fill replaceable parameters {0}, {1}, etc.
  +     * 
  +     * @since 3.0
  +     * 
  +     **/
   
  +    protected String formatString(String pattern, Object[] args)
  +    {
           return MessageFormat.format(pattern, args);
       }
   
       /**
  -     *  Convienience method for invoking {@link #getString(String, Locale, Object[])}.
  +     *  Convienience method for invoking {@link #formatString(String, Locale, Object[])}.
        * 
  -     *  @since 2.1
  +     *  @since 3.0
        * 
        **/
   
  -    protected String getString(String key, Locale locale, Object arg)
  +    protected String formatString(String pattern, Object arg)
       {
  -        return getString(key, locale, new Object[] { arg });
  +        return formatString(pattern, new Object[] { arg });
       }
   
       /**
  -     *  Convienience method for invoking {@link #getString(String, Locale, Object[])}.
  +     *  Convienience method for invoking {@link #formatString(String, Locale, Object[])}.
        * 
  -     *  @since 2.1
  +     *  @since 3.0
        * 
        **/
   
  -    protected String getString(String key, Locale locale, Object arg1, Object arg2)
  +    protected String formatString(String pattern, Object arg1, Object arg2)
       {
  -        return getString(key, locale, new Object[] { arg1, arg2 });
  +        return formatString(pattern, new Object[] { arg1, arg2 });
       }
   
       /**
  @@ -231,12 +257,27 @@
   
           if (_required && isNull)
               throw new ValidatorException(
  -                getString("field-is-required", field.getPage().getLocale(), field.getDisplayName()),
  +                buildRequiredMessage(field),
                   ValidationConstraint.REQUIRED);
   
           return isNull;
       }
   
  +    /** 
  +     * Builds an error message indicating a value for a required
  +     * field was not supplied.
  +     * 
  +     * @since 3.0
  +     */
  +
  +    protected String buildRequiredMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(_requiredMessage, "field-is-required", field.getPage().getLocale());
  +
  +        return formatString(pattern, field.getDisplayName());
  +    }
  +
       /**
        *  This implementation does nothing.  Subclasses may supply their own implementation.
        * 
  @@ -329,6 +370,23 @@
       public void setClientScriptingEnabled(boolean clientScriptingEnabled)
       {
           _clientScriptingEnabled = clientScriptingEnabled;
  +    }
  +
  +    public String getRequiredMessage()
  +    {
  +        return _requiredMessage;
  +    }
  +
  +    /**
  +     * Overrides the <code>field-is-required</code> bundle key.
  +     * Parameter {0} is the display name of the field.
  +     * 
  +     * @since 3.0
  +     */
  +
  +    public void setRequiredMessage(String string)
  +    {
  +        _requiredMessage = string;
       }
   
   }
  
  
  
  1.3       +37 -70    jakarta-tapestry/framework/src/org/apache/tapestry/valid/StringValidator.java
  
  Index: StringValidator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/StringValidator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- StringValidator.java	15 Mar 2003 21:22:22 -0000	1.2
  +++ StringValidator.java	18 Apr 2003 16:14:26 -0000	1.3
  @@ -77,56 +77,10 @@
   
   public class StringValidator extends BaseValidator
   {
  -    private static final class StaticStringValidator extends StringValidator
  -    {
  -        private static final String UNSUPPORTED_MESSAGE =
  -            "Changes to property values are not allowed.";
  -
  -        private StaticStringValidator(boolean required)
  -        {
  -            super(required);
  -        }
  -
  -        /** @throws UnsupportedOperationException **/
  -
  -        public void setMinimumLength(int minimumLength)
  -        {
  -            throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
  -        }
  -
  -        /** @throws UnsupportedOperationException **/
  -
  -        public void setRequired(boolean required)
  -        {
  -            throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
  -        }
  -
  -        /** @throws UnsupportedOperationException **/
  -
  -        public void setClientScriptingEnabled(boolean clientScriptingEnabled)
  -        {
  -            throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
  -        }
  -    }
  -
  -    /**
  -     *  Returns a shared instance of a StringValidator with the required flag set.
  -     *  The instance is not modifiable.
  -     *
  -     **/
  -
  -    public static final StringValidator REQUIRED = new StaticStringValidator(true);
  -
  -    /**
  -     *  Returns a shared instance of a StringValidator with the required flag cleared.
  -     *  The instance is not modifiable.
  -     *
  -     **/
  -
  -    public static final StringValidator OPTIONAL = new StaticStringValidator(false);
  -
       private int _minimumLength;
   
  +    private String _minimumLengthMessage;
  +
       /** @since 2.2 **/
   
       private String _scriptPath = "/org/apache/tapestry/valid/StringValidator.script";
  @@ -154,16 +108,9 @@
               return null;
   
           if (_minimumLength > 0 && input.length() < _minimumLength)
  -        {
  -            String errorMessage =
  -                getString(
  -                    "field-too-short",
  -                    field.getPage().getLocale(),
  -                    Integer.toString(_minimumLength),
  -                    field.getDisplayName());
  -
  -            throw new ValidatorException(errorMessage, ValidationConstraint.MINIMUM_WIDTH);
  -        }
  +            throw new ValidatorException(
  +                buildMinimumLengthMessage(field),
  +                ValidationConstraint.MINIMUM_WIDTH);
   
           return input;
       }
  @@ -197,20 +144,11 @@
   
           Map symbols = new HashMap();
   
  -        Locale locale = field.getPage().getLocale();
  -        String displayName = field.getDisplayName();
  -
           if (isRequired())
  -            symbols.put("requiredMessage", getString("field-is-required", locale, displayName));
  +            symbols.put("requiredMessage", buildRequiredMessage(field));
   
           if (_minimumLength > 0)
  -            symbols.put(
  -                "minimumLengthMessage",
  -                getString(
  -                    "field-too-short",
  -                    locale,
  -                    Integer.toString(_minimumLength),
  -                    displayName));
  +            symbols.put("minimumLengthMessage", buildMinimumLengthMessage(field));
   
           processValidatorScript(_scriptPath, cycle, field, symbols);
       }
  @@ -238,6 +176,35 @@
       public void setScriptPath(String scriptPath)
       {
           _scriptPath = scriptPath;
  +    }
  +
  +    /** @since 3.0 */
  +    public String getMinimumLengthMessage()
  +    {
  +        return _minimumLengthMessage;
  +    }
  +
  +    /** 
  +     * Overrides the <code>field-too-short</code> bundle key.
  +     * Parameter {0} is the minimum length.
  +     * Parameter {1} is the display name of the field.
  +     * 
  +     * @since 3.0
  +     */
  +
  +    public void setMinimumLengthMessage(String string)
  +    {
  +        _minimumLengthMessage = string;
  +    }
  +
  +    /** @since 3.0 */
  +
  +    protected String buildMinimumLengthMessage(IFormComponent field)
  +    {
  +        String pattern =
  +            getPattern(_minimumLengthMessage, "field-too-short", field.getPage().getLocale());
  +
  +        return formatString(pattern, Integer.toString(_minimumLength), field.getDisplayName());
       }
   
   }
  
  
  
  1.2       +12 -12    jakarta-tapestry/framework/src/org/apache/tapestry/valid/ValidationStrings_de.properties
  
  Index: ValidationStrings_de.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/valid/ValidationStrings_de.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ValidationStrings_de.properties	5 Mar 2003 22:59:40 -0000	1.1
  +++ ValidationStrings_de.properties	18 Apr 2003 16:14:26 -0000	1.2
  @@ -1,17 +1,17 @@
   # $Id$
   
  -field-is-required=Eingabefeld "{0}" ist ein Pflichfeld.
  -field-too-short=Sie m�ssen min. "{0}" Zeichen fuer Eingabefeld {1}.
  +field-is-required=Eingabefeld {0} ist ein Pflichfeld.
  +field-too-short=Sie m�ssen min. {0} Zeichen fuer Eingabefeld {1}.
   
  -invalid-date-format=Eingabefeld "{0}" hat ein falsches Datumsformat (Eingabeformat ist {1}).
  -invalid-int-format=Eingabefeld "{0}" erwartet ein numerischen Wert.
  -invalid-format=Eingabefeld "{0}" hat nicht das gew�nschte Format.
  -invalid-numeric-format=Eingabefeld "{0}" erwartet ein numerischen Wert.
  +invalid-date-format=Eingabefeld {0} hat ein falsches Datumsformat (Eingabeformat ist {1}).
  +invalid-int-format=Eingabefeld {0} erwartet ein numerischen Wert.
  +invalid-format=Eingabefeld {0} hat nicht das gew�nschte Format.
  +invalid-numeric-format=Eingabefeld {0} erwartet ein numerischen Wert.
   
  -date-too-early=Datum f�r Eingabefeld "{0}" kann nur der {1} oder sp�ter sein.
  -date-too-late=Datum f�r Eingabefeld "{0}" kann nur der {1} oder fr�her sein.
  +date-too-early=Datum f�r Eingabefeld {0} kann nur der {1} oder sp�ter sein.
  +date-too-late=Datum f�r Eingabefeld {0} kann nur der {1} oder fr�her sein.
   
  -number-too-small=Wert f�r Eingabefeld "{0}" darf nicht kleiner sein als {1}.
  -number-too-large=Wert f�r Eingabefeld "{0}" darf nicht gr�sser sein als {1}.
  +number-too-small=Wert f�r Eingabefeld {0} darf nicht kleiner sein als {1}.
  +number-too-large=Wert f�r Eingabefeld {0} darf nicht gr�sser sein als {1}.
   
  -number-range=Wert f�r Eingabefeld "{0}" darf nur zwischen {1} und {2} liegen.
  +number-range=Wert f�r Eingabefeld {0} darf nur zwischen {1} und {2} liegen.
  
  
  
  1.155     +3 -2      jakarta-tapestry/web/new.html
  
  Index: new.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/web/new.html,v
  retrieving revision 1.154
  retrieving revision 1.155
  diff -u -r1.154 -r1.155
  --- new.html	17 Apr 2003 21:33:59 -0000	1.154
  +++ new.html	18 Apr 2003 16:14:27 -0000	1.155
  @@ -33,7 +33,8 @@
   [ 18490 ] compile warning for Workbench 
   [ 18013 ] typo in EvenOdd javadoc
   [ 18607 ] Check for unimplemented abstract methods    
  -[ 17904 ] Ongoing LGPL Issues  
  +[ 17904 ] Ongoing LGPL Issues 
  +[ 19153 ] Easier way to override validation messages  
   </pre>
   
   <h3>Release 2.4-alpha-5</h3>
  
  
  
  1.4       +7 -3      jakarta-tapestry/examples/Workbench/context/WEB-INF/Chart.page
  
  Index: Chart.page
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/examples/Workbench/context/WEB-INF/Chart.page,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Chart.page	12 Mar 2003 16:50:11 -0000	1.3
  +++ Chart.page	18 Apr 2003 16:14:28 -0000	1.4
  @@ -7,8 +7,12 @@
   <page-specification class="org.apache.tapestry.workbench.chart.ChartPage">
   
     <bean name="delegate" class="org.apache.tapestry.workbench.WorkbenchValidationDelegate"/>
  +  
  +	<bean name="required" class="org.apache.tapestry.valid.StringValidator" lifecycle="page">
  +	  <set-property name="required" expression="true"/>
  +	</bean>
   
  -  <bean name="intValidator" class="org.apache.tapestry.valid.NumberValidator">
  +  <bean name="intValidator" class="org.apache.tapestry.valid.NumberValidator" lifecycle="page">
     	<set-property name="required" expression="true"/>
     	<set-property name="minimum" expression="0"/>
     </bean>
  @@ -31,7 +35,7 @@
     <component id="inputName" type="ValidField">
     	<static-binding name="displayName" value="Name"/>
     	<binding name="value" expression="plotValue.name"/>
  -  	<binding name="validator" expression="@org.apache.tapestry.valid.StringValidator@REQUIRED"/>
  +  	<binding name="validator" expression="beans.required"/>
     </component>
   
     <component id="inputValue" type="ValidField">	
  
  
  
  1.2       +53 -24    jakarta-tapestry/framework/src/org/apache/tapestry/spec/IContainedComponent.java
  
  Index: IContainedComponent.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/spec/IContainedComponent.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- IContainedComponent.java	15 Apr 2003 18:14:11 -0000	1.1
  +++ IContainedComponent.java	18 Apr 2003 16:14:28 -0000	1.2
  @@ -1,28 +1,57 @@
  -/* ***** BEGIN LICENSE BLOCK *****
  - * Version: MPL 1.1
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
    *
  - * The contents of this file are subject to the Mozilla Public License Version
  - * 1.1 (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.mozilla.org/MPL/
  - *
  - * Software distributed under the License is distributed on an "AS IS" basis,
  - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  - * for the specific language governing rights and limitations under the
  - * License.
  - *
  - * The Original Code is Spindle, an Eclipse Plugin for Tapestry.
  - *
  - * The Initial Developer of the Original Code is
  - * Intelligent Works Incorporated.
  - * Portions created by the Initial Developer are Copyright (C) 2003
  - * the Initial Developer. All Rights Reserved.
  - *
  - * Contributor(s):
  - * 
  - *  glongman@intelligentworks.com
  + * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
  + * reserved.
    *
  - * ***** END LICENSE BLOCK ***** */
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
  + *
  + * 4. The names "Apache" and "Apache Software Foundation", "Tapestry" 
  + *    must not be used to endorse or promote products derived from this
  + *    software without prior written permission. For written
  + *    permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache" 
  + *    or "Tapestry", nor may "Apache" or "Tapestry" appear in their 
  + *    name, without prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE TAPESTRY CONTRIBUTOR COMMUNITY
  + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
  + *
  + */
   
   package org.apache.tapestry.spec;
   
  
  
  
  1.3       +52 -23    jakarta-tapestry/framework/src/org/apache/tapestry/spec/IListenerBindingSpecification.java
  
  Index: IListenerBindingSpecification.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tapestry/framework/src/org/apache/tapestry/spec/IListenerBindingSpecification.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- IListenerBindingSpecification.java	17 Apr 2003 21:33:57 -0000	1.2
  +++ IListenerBindingSpecification.java	18 Apr 2003 16:14:28 -0000	1.3
  @@ -1,28 +1,57 @@
  -/* ***** BEGIN LICENSE BLOCK *****
  - * Version: MPL 1.1
  +/* ====================================================================
  + * The Apache Software License, Version 1.1
    *
  - * The contents of this file are subject to the Mozilla Public License Version
  - * 1.1 (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.mozilla.org/MPL/
  - *
  - * Software distributed under the License is distributed on an "AS IS" basis,
  - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  - * for the specific language governing rights and limitations under the
  - * License.
  - *
  - * The Original Code is Spindle, an Eclipse Plugin for Tapestry.
  - *
  - * The Initial Developer of the Original Code is
  - * Intelligent Works Incorporated.
  - * Portions created by the Initial Developer are Copyright (C) 2003
  - * the Initial Developer. All Rights Reserved.
  - *
  - * Contributor(s):
  - * 
  - *  glongman@intelligentworks.com
  + * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
  + * reserved.
    *
  - * ***** END LICENSE BLOCK ***** */
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + *
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + *
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in
  + *    the documentation and/or other materials provided with the
  + *    distribution.
  + *
  + * 3. The end-user documentation included with the redistribution,
  + *    if any, must include the following acknowledgment:
  + *       "This product includes software developed by the
  + *        Apache Software Foundation (http://apache.org/)."
  + *    Alternately, this acknowledgment may appear in the software itself,
  + *    if and wherever such third-party acknowledgments normally appear.
  + *
  + * 4. The names "Apache" and "Apache Software Foundation", "Tapestry" 
  + *    must not be used to endorse or promote products derived from this
  + *    software without prior written permission. For written
  + *    permission, please contact apache@apache.org.
  + *
  + * 5. Products derived from this software may not be called "Apache" 
  + *    or "Tapestry", nor may "Apache" or "Tapestry" appear in their 
  + *    name, without prior written permission of the Apache Software Foundation.
  + *
  + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  + * DISCLAIMED.  IN NO EVENT SHALL THE TAPESTRY CONTRIBUTOR COMMUNITY
  + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + * ====================================================================
  + *
  + * This software consists of voluntary contributions made by many
  + * individuals on behalf of the Apache Software Foundation.  For more
  + * information on the Apache Software Foundation, please see
  + * <http://www.apache.org/>.
  + *
  + */
   
   package org.apache.tapestry.spec;