Author: andyhot
Date: Fri Mar 16 22:21:13 2007
New Revision: 519241

URL: http://svn.apache.org/viewvc?view=rev&rev=519241
Log:
TAPESTRY-410:Match-differ validator (server and client side)

Added:
    
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/validator/Identity.java
    
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/validator/TestIdentity.java
Modified:
    
tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.form.validator.xml

Modified: 
tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.form.validator.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.form.validator.xml?view=diff&rev=519241&r1=519240&r2=519241
==============================================================================
--- 
tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.form.validator.xml
 (original)
+++ 
tapestry/tapestry4/trunk/tapestry-framework/src/descriptor/META-INF/tapestry.form.validator.xml
 Fri Mar 16 22:21:13 2007
@@ -49,7 +49,9 @@
     <validator name="min" class="Min"/>
     <validator name="minDate" class="MinDate"/>
     <validator name="minLength" class="MinLength"/>
-    <validator name="pattern" class="Pattern"/>    
+    <validator name="pattern" class="Pattern"/>
+    <validator name="match" configurable="true" class="Identity"/>
+    <validator name="differ" configurable="true" class="Identity"/>    
   </contribution>
   
   <service-point id="ValidatorFactory">

Added: 
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/validator/Identity.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/validator/Identity.java?view=auto&rev=519241
==============================================================================
--- 
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/validator/Identity.java
 (added)
+++ 
tapestry/tapestry4/trunk/tapestry-framework/src/java/org/apache/tapestry/form/validator/Identity.java
 Fri Mar 16 22:21:13 2007
@@ -0,0 +1,157 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
+//
+// 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.apache.tapestry.form.validator;
+
+import org.apache.tapestry.IMarkupWriter;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.form.FormComponentContributorContext;
+import org.apache.tapestry.form.IFormComponent;
+import org.apache.tapestry.form.ValidationMessages;
+import org.apache.tapestry.json.JSONLiteral;
+import org.apache.tapestry.json.JSONObject;
+import org.apache.tapestry.valid.ValidationConstants;
+import org.apache.tapestry.valid.ValidatorException;
+import org.apache.tapestry.valid.ValidationConstraint;
+
+/**
+ * Validates that the input value is the same as the value of another field.
+ * This validator can also work in 'differ' mode. 
+ * <p/>
+ * Apply this validator to the second field in question and define the name
+ * of the component against which to compare the current value.
+ *
+ * @since 4.1.2
+ */
+public class Identity extends BaseValidator {
+    private String _fieldName;
+    private int _matchType;
+    private String _identityMessage;
+
+    private static final int DIFFER = 0;
+    private static final int MATCH = 1;
+
+
+    public Identity() {
+        super();
+    }
+
+
+    public Identity(String initializer) {
+        super(initializer);
+    }
+
+    public String toString(IFormComponent field, Object value) {
+        if (value == null)
+            return null;
+
+        return value.toString();
+    }
+
+    public void validate(IFormComponent field, ValidationMessages messages, 
Object object)
+            throws ValidatorException {
+        IFormComponent referent = (IFormComponent) 
field.getContainer().getComponent(_fieldName);
+        Object referentValue = referent.getBinding("value").getObject();
+
+        //TODO: if component is null treat _fieldName as an ognl expression
+        boolean notEq = notEqual(referentValue, object);
+
+        if (_matchType == MATCH ? notEq : !notEq)
+            throw new ValidatorException(buildIdentityMessage(messages, field, 
referent),
+                    ValidationConstraint.CONSISTENCY);
+    }
+    
+    public void renderContribution(IMarkupWriter writer, IRequestCycle cycle,
+            FormComponentContributorContext context, IFormComponent field)
+    {
+        if(field.isDisabled())
+            return;
+        
+        IFormComponent referent = (IFormComponent) 
field.getContainer().getComponent(_fieldName);
+        
+        JSONObject profile = context.getProfile();
+        
+        if (!profile.has(ValidationConstants.CONSTRAINTS)) {
+            profile.put(ValidationConstants.CONSTRAINTS, new JSONObject());
+        }
+        JSONObject cons = 
profile.getJSONObject(ValidationConstants.CONSTRAINTS);
+        
+        String func = (_matchType == MATCH) ? 
+            "tapestry.form.validation.isEqual" :
+            "tapestry.form.validation.isNotEqual";
+        
+        accumulateProperty(cons, field.getClientId(), 
+                new JSONLiteral("[" + func + ",\""
+                        + referent.getClientId() + "\"]"));                
+        
+        accumulateProfileProperty(field, profile, 
+                ValidationConstants.CONSTRAINTS, buildIdentityMessage(context, 
field, referent));        
+    }
+
+    public String getMatch() {
+        return _fieldName;
+    }
+
+    public void setMatch(String field) {
+        _fieldName = field;
+        _matchType = MATCH;
+
+    }
+
+    public String getDiffer() {
+        return _fieldName;
+    }
+
+    public void setDiffer(String field) {
+        _fieldName = field;
+        _matchType = DIFFER;
+    }
+
+
+    /** @since 3.0 */
+    public String getIdentityMessage() {
+        return _identityMessage;
+    }
+
+    /**
+     * 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 setIdentityMessage(String string) {
+        _identityMessage = string;
+    }
+
+    /** @since 3.0 */
+
+    protected String buildIdentityMessage(ValidationMessages messages, 
IFormComponent field, IFormComponent referent) {
+        Object[] parameters = new Object[]{
+                field.getDisplayName(), new Integer(_matchType), 
referent.getDisplayName()
+        };
+        return messages.formatValidationMessage(_identityMessage,
+                "invalid-field-equality", parameters);
+
+    }
+
+    private boolean notEqual(Object o1, Object o2) {
+        if (o1 == null && o2 == null)
+            return false;
+        if (o1 == null || o2 == null)
+            return true;
+        return !o1.equals(o2);
+    }
+
+}
\ No newline at end of file

Added: 
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/validator/TestIdentity.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/validator/TestIdentity.java?view=auto&rev=519241
==============================================================================
--- 
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/validator/TestIdentity.java
 (added)
+++ 
tapestry/tapestry4/trunk/tapestry-framework/src/test/org/apache/tapestry/form/validator/TestIdentity.java
 Fri Mar 16 22:21:13 2007
@@ -0,0 +1,167 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
+//
+// 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.apache.tapestry.form.validator;
+
+import java.util.Locale;
+import org.apache.tapestry.IBinding;
+import org.apache.tapestry.IComponent;
+import org.apache.tapestry.form.ValidationMessagesImpl;
+import org.easymock.EasyMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.aryEq;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.isNull;
+import static org.easymock.EasyMock.checkOrder;
+
+import org.apache.tapestry.IMarkupWriter;
+import org.apache.tapestry.IRequestCycle;
+import org.apache.tapestry.form.FormComponentContributorContext;
+import org.apache.tapestry.form.IFormComponent;
+import org.apache.tapestry.form.ValidationMessages;
+import org.apache.tapestry.json.JSONObject;
+import org.apache.tapestry.valid.ValidationConstraint;
+import org.apache.tapestry.valid.ValidationStrings;
+import org.apache.tapestry.valid.ValidatorException;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for [EMAIL PROTECTED] org.apache.tapestry.form.validator.Identity}.
+ * 
+ * @since 4.1.2
+ */
[EMAIL PROTECTED]
+public class TestIdentity extends BaseValidatorTestCase
+{
+    public void testOK() throws Exception
+    {
+        IFormComponent field = newField();
+        IFormComponent otherField = newField();                
+        
+        trainGetContainerAndComponent(field, "newPass", otherField);
+        trainGetValueBinding(otherField, "pass");        
+        
+        ValidationMessages messages = newMessages();
+
+        replay();
+
+        new Identity("match=newPass").validate(field, messages, "pass");
+
+        verify();
+    }
+
+    public void testFail()
+    {
+        IFormComponent field = newField();
+        IFormComponent otherField = newField();                
+        
+        trainGetContainerAndComponent(field, "newPass", otherField);
+        trainGetValueBinding(otherField, "pass");
+        expect(field.getDisplayName()).andReturn("Password-1");
+        expect(otherField.getDisplayName()).andReturn("Password-2");
+        
+        ValidationMessages messages = newMessages();
+        trainIdentityMessages(messages, "Password-1", "Password-2", 1, 
"err1");        
+
+        replay();
+
+        try
+        {
+            new Identity("match=newPass").validate(field, messages, 
"passOTHER");
+        }
+        catch (ValidatorException ex)
+        {
+            assertEquals(ex.getMessage(), "err1");
+            assertEquals(ex.getConstraint(), ValidationConstraint.CONSISTENCY);
+        }
+    }
+
+    public void testFailCustomMessage()
+    {
+        IFormComponent field = newField();
+        IFormComponent otherField = newField();                
+        
+        trainGetContainerAndComponent(field, "newPass", otherField);
+        trainGetValueBinding(otherField, "pass");
+        expect(field.getDisplayName()).andReturn("Password-1");
+        expect(otherField.getDisplayName()).andReturn("Password-2");
+        
+        ValidationMessages messages = newMessages();
+        trainIdentityMessages(messages, "Password-1", "Password-2", 0, 
"error");
+
+        replay();
+
+        try
+        {
+            new Identity("differ=newPass,message=Should 
differ!").validate(field, messages, "pass");
+        }
+        catch (ValidatorException ex)
+        {
+            assertEquals(ex.getMessage(), "error");
+            assertEquals(ex.getConstraint(), ValidationConstraint.CONSISTENCY);
+        }
+    }
+
+    public void test_Render_Contribution()
+    {
+        JSONObject json = new JSONObject();
+        
+        IFormComponent field = newField(/*);//*/"Password", "pass1");
+        expect(field.isDisabled()).andReturn(false);
+        
+        IFormComponent otherField = newField(/*);//*/"Verify Password", 
"pass2");
+        trainGetContainerAndComponent(field, "other", otherField);
+        
+        FormComponentContributorContext context = 
newMock(FormComponentContributorContext.class);        
+        expect(context.getProfile()).andReturn(json);        
+                
+        trainIdentityMessages(context, "Password", "Verify Password", 1, 
"Fields must match");        
+        
+        IMarkupWriter writer = newWriter();
+        IRequestCycle cycle = newCycle();
+        
+        replay();
+        
+        new Identity("match=other").renderContribution(writer, cycle, context, 
field);
+        
+        verify();
+        
+        
assertEquals("{\"constraints\":{\"pass1\":[[tapestry.form.validation.isEqual,\"pass2\"]]},"
+                + "\"pass1\":{\"constraints\":[\"Fields must match\"]}}",
+                json.toString());
+    }    
+    
+    public void testNotRequired()
+    {
+        assertEquals(false, new Identity().isRequired());
+    }
+    
+    private void trainGetContainerAndComponent(IFormComponent field, String 
name, IFormComponent other) {
+        IComponent container = newComponent();
+        expect(field.getContainer()).andReturn(container);
+        expect(container.getComponent(name)).andReturn(other);        
+    }
+    
+    private void trainGetValueBinding(IFormComponent field, String value) {
+        IBinding ret = newBinding(value);
+        expect(field.getBinding("value")).andReturn(ret);
+    }   
+
+    private void trainIdentityMessages(ValidationMessages messages, String 
name1, String name2, int match, String result)
+    {
+        trainFormatMessage(messages, null, "invalid-field-equality", 
+                new Object[]{ name1, new Integer(match), name2 }, 
+                result);
+    }    
+}


Reply via email to