You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/11/16 18:07:49 UTC
svn commit: r595742 - in /tapestry/tapestry5/trunk:
tapestry-core/src/main/java/org/apache/tapestry/corelib/base/
tapestry-core/src/main/java/org/apache/tapestry/corelib/components/
tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ tape...
Author: hlship
Date: Fri Nov 16 09:07:48 2007
New Revision: 595742
URL: http://svn.apache.org/viewvc?rev=595742&view=rev
Log:
TAPESTRY-1476: Component events for input translation and validation
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapper.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapperTest.java
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentTranslatorWrapper.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/runtime/ComponentEventException.java
tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/EventMethodTranslate.java
tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java Fri Nov 16 09:07:48 2007
@@ -20,6 +20,7 @@
import org.apache.tapestry.annotations.Environmental;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.corelib.internal.ComponentTranslatorWrapper;
+import org.apache.tapestry.corelib.internal.ComponentValidatorWrapper;
import org.apache.tapestry.ioc.Messages;
import org.apache.tapestry.ioc.annotations.Inject;
import org.apache.tapestry.services.*;
@@ -169,6 +170,7 @@
*/
protected abstract void writeFieldTag(MarkupWriter writer, String value);
+ @SuppressWarnings({"unchecked"})
@Override
protected final void processSubmission(FormSupport formSupport, String elementName)
{
@@ -180,13 +182,13 @@
try
{
- Translator wrapper = new ComponentTranslatorWrapper(_resources, _translate);
+ Translator translatorWrapper = new ComponentTranslatorWrapper(_resources, _translate);
- Object translated = wrapper.parseClient(rawValue, messages);
+ Object translated = translatorWrapper.parseClient(rawValue, messages);
- // TODO: A wrapper for validation as well?
+ FieldValidator validatorWrapper = new ComponentValidatorWrapper(_resources, _validate);
- _validate.validate(translated);
+ validatorWrapper.validate(translated);
_value = translated;
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/components/Select.java Fri Nov 16 09:07:48 2007
@@ -19,6 +19,7 @@
import org.apache.tapestry.annotations.Environmental;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.corelib.base.AbstractField;
+import org.apache.tapestry.corelib.internal.ComponentValidatorWrapper;
import org.apache.tapestry.internal.util.SelectModelRenderer;
import org.apache.tapestry.ioc.annotations.Inject;
import org.apache.tapestry.services.*;
@@ -104,6 +105,7 @@
@Inject
private ValueEncoderSource _valueEncoderSource;
+ @SuppressWarnings({"unchecked"})
@Override
protected void processSubmission(FormSupport formSupport, String elementName)
{
@@ -111,16 +113,17 @@
Object selectedValue = _encoder.toValue(primaryKey);
+ FieldValidator wrappedValidator = new ComponentValidatorWrapper(_resources, _validate);
+
try
{
- _validate.validate(selectedValue);
+ wrappedValidator.validate(selectedValue);
_value = selectedValue;
}
catch (ValidationException ex)
{
_tracker.recordError(this, ex.getMessage());
- return;
}
}
@@ -167,13 +170,9 @@
if (type == null) return null;
- return _fieldValidatorDefaultSource.createDefaultValidator(
- this,
- _resources.getId(),
- _resources.getContainerMessages(),
- _locale,
- type,
- _resources.getAnnotationProvider("value"));
+ return _fieldValidatorDefaultSource.createDefaultValidator(this, _resources.getId(),
+ _resources.getContainerMessages(), _locale, type,
+ _resources.getAnnotationProvider("value"));
}
Binding defaultValue()
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentTranslatorWrapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentTranslatorWrapper.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentTranslatorWrapper.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentTranslatorWrapper.java Fri Nov 16 09:07:48 2007
@@ -68,11 +68,9 @@
}
catch (ComponentEventException ex)
{
- Throwable cause = ex.getCause();
+ ValidationException ve = ex.get(ValidationException.class);
- if (cause instanceof ValidationException) throw (ValidationException) cause;
-
- // Rethrow the event exception for reporting higher up.
+ if (ve != null) throw ve;
throw ex;
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapper.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapper.java?rev=595742&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapper.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapper.java Fri Nov 16 09:07:48 2007
@@ -0,0 +1,55 @@
+package org.apache.tapestry.corelib.internal;
+
+import org.apache.tapestry.ComponentResources;
+import org.apache.tapestry.FieldValidator;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.ValidationException;
+import org.apache.tapestry.runtime.ComponentEventException;
+
+/**
+ * Wraps around a component, allowing it to perform input validation using
+ * an event.
+ */
+@SuppressWarnings("unchecked")
+public class ComponentValidatorWrapper implements FieldValidator
+{
+ static final String VALIDATE_EVENT = "validate";
+
+ private final ComponentResources _resources;
+ private final FieldValidator _validator;
+
+ public ComponentValidatorWrapper(ComponentResources resources, FieldValidator delegate)
+ {
+ _resources = resources;
+ _validator = delegate;
+ }
+
+ /**
+ * Invokes a "validate" event on the component, passing the value as context.
+ *
+ * @param value
+ * @throws ValidationException
+ */
+ public void validate(Object value) throws ValidationException
+ {
+ try
+ {
+ _resources.triggerEvent(VALIDATE_EVENT, new Object[]{value}, null);
+ }
+ catch (ComponentEventException ex)
+ {
+ ValidationException ve = ex.get(ValidationException.class);
+
+ if (ve != null) throw ve;
+
+ throw ex;
+ }
+
+ _validator.validate(value);
+ }
+
+ public void render(MarkupWriter writer)
+ {
+ _validator.render(writer);
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/runtime/ComponentEventException.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/runtime/ComponentEventException.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/runtime/ComponentEventException.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/runtime/ComponentEventException.java Fri Nov 16 09:07:48 2007
@@ -37,4 +37,21 @@
{
return _methodDescription;
}
+
+ /**
+ * Checks to see if the root cause of this exception is assignable to the provided type. Returns the
+ * root cause, cast to the given value if so, or null otherwise.
+ *
+ * @param exceptionType type of exception to check for
+ * @return the root cause, or null if the root cause is null or not assignable to the provided exception type
+ */
+ public <T extends Exception> T get(Class<T> exceptionType)
+ {
+ Throwable cause = getCause();
+
+ if (cause != null && exceptionType.isAssignableFrom(cause.getClass())) return exceptionType.cast(cause);
+
+ return null;
+ }
+
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/site/apt/guide/validation.apt Fri Nov 16 09:07:48 2007
@@ -294,8 +294,25 @@
{{{../../apidocs/org/apache/tapestry/ValidationException.html}ValidationException}} to indicate a value
that can't be parsed.
- <<Caution:>> These two events are exclusively on the <server side>. Client side validations, in particular,
- will not have access to the "parseclient" event. This means that, in certain circumstances,
+ Now, what if you want to perform your own custom validation? That's another event: "validate":
+
++---+
+ void onValidateFromCount(Integer value) throws ValidationException
+ {
+ if (value == null) return;
+
+ if (value.equals(13)) throw new ValidationException("Thirteen is an unlucky number.");
+ }
++---+
+
+ This event gets fired <<before>> the normal validators, therefore you have to watch out
+ for nulls, even if the field is marked as required. It gets the <parsed> value (not the string from
+ the client, but the object value from the translator, or from the "parseclient" event handler).
+
+ The method may not return value, but may throw a ValidationException to indicate a problem with
+ the value.
+
+ <<Caution:>> These events are exclusively on the <server side>.
+ This means that, in certain circumstances,
an input value will be rejected on the client side even though it is valid on the server side.
- <Coming soon: an additional event for validating the parsed value.>
\ No newline at end of file
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapperTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapperTest.java?rev=595742&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapperTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/corelib/internal/ComponentValidatorWrapperTest.java Fri Nov 16 09:07:48 2007
@@ -0,0 +1,90 @@
+package org.apache.tapestry.corelib.internal;
+
+import org.apache.tapestry.*;
+import org.apache.tapestry.runtime.ComponentEventException;
+import org.apache.tapestry.test.TapestryTestCase;
+import org.easymock.EasyMock;
+import org.testng.annotations.Test;
+
+public class ComponentValidatorWrapperTest extends TapestryTestCase
+{
+ @Test
+ public void render_is_a_pass_thru()
+ {
+ ComponentResources resources = mockComponentResources();
+ FieldValidator fv = mockFieldValidator();
+ MarkupWriter writer = mockMarkupWriter();
+
+ fv.render(writer);
+
+ replay();
+
+ FieldValidator wrapper = new ComponentValidatorWrapper(resources, fv);
+
+ wrapper.render(writer);
+
+ verify();
+ }
+
+ @SuppressWarnings({"unchecked"})
+ @Test
+ public void event_triggered_before_delegate_invoked() throws Exception
+ {
+ getMocksControl().checkOrder(true);
+
+ ComponentResources resources = mockComponentResources();
+ FieldValidator fv = mockFieldValidator();
+
+ Object value = new Object();
+
+ ComponentEventHandler handler = null;
+
+ expect(resources.triggerEvent(EasyMock.eq(ComponentValidatorWrapper.VALIDATE_EVENT),
+ EasyMock.aryEq(new Object[]{value}), EasyMock.eq(handler))).andReturn(true);
+
+ fv.validate(value);
+
+ replay();
+
+ FieldValidator wrapper = new ComponentValidatorWrapper(resources, fv);
+
+ wrapper.validate(value);
+
+ verify();
+ }
+
+ @SuppressWarnings({"unchecked", "ThrowableInstanceNeverThrown"})
+ @Test
+ public void event_trigger_throws_validation_exception() throws Exception
+ {
+ ComponentResources resources = mockComponentResources();
+ FieldValidator fv = mockFieldValidator();
+
+ Object value = new Object();
+
+ ValidationException ve = new ValidationException("Bah!");
+ ComponentEventException cee = new ComponentEventException(ve.getMessage(), null, ve);
+
+ ComponentEventHandler handler = null;
+
+ expect(resources.triggerEvent(EasyMock.eq(ComponentValidatorWrapper.VALIDATE_EVENT),
+ EasyMock.aryEq(new Object[]{value}), EasyMock.eq(handler))).andThrow(cee);
+
+
+ replay();
+
+ FieldValidator wrapper = new ComponentValidatorWrapper(resources, fv);
+
+
+ try
+ {
+ wrapper.validate(value);
+ unreachable();
+ }
+ catch (ValidationException ex)
+ {
+ assertSame(ex, ve);
+ }
+ verify();
+ }
+}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Fri Nov 16 09:07:48 2007
@@ -1151,5 +1151,12 @@
assertTextPresent("Count: [0]");
assertFieldValue("count", "zero");
+
+ // Try the server-side custom exception reporting.
+
+ type("count", "13");
+ clickAndWait(SUBMIT);
+
+ assertTextPresent("Thirteen is an unlucky number.");
}
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/EventMethodTranslate.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/EventMethodTranslate.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/EventMethodTranslate.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/integration/app1/pages/EventMethodTranslate.java Fri Nov 16 09:07:48 2007
@@ -52,4 +52,12 @@
return null;
}
+
+ void onValidateFromCount(Integer count) throws ValidationException
+ {
+ // count may be null
+ if (count == null) return;
+
+ if (count.equals(13)) throw new ValidationException("Thirteen is an unlucky number.");
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java?rev=595742&r1=595741&r2=595742&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java (original)
+++ tapestry/tapestry5/trunk/tapestry-upload/src/main/java/org/apache/tapestry/upload/components/Upload.java Fri Nov 16 09:07:48 2007
@@ -18,6 +18,7 @@
import org.apache.tapestry.annotations.Environmental;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.corelib.base.AbstractField;
+import org.apache.tapestry.corelib.internal.ComponentValidatorWrapper;
import org.apache.tapestry.ioc.annotations.Inject;
import org.apache.tapestry.services.FieldValidatorDefaultSource;
import org.apache.tapestry.services.FormSupport;
@@ -76,13 +77,9 @@
if (type == null) return null;
- return _fieldValidatorDefaultSource.createDefaultValidator(
- this,
- _resources.getId(),
- _resources.getContainerMessages(),
- _locale,
- type,
- _resources.getAnnotationProvider("value"));
+ return _fieldValidatorDefaultSource.createDefaultValidator(this, _resources.getId(),
+ _resources.getContainerMessages(), _locale, type,
+ _resources.getAnnotationProvider("value"));
}
public Upload()
@@ -90,8 +87,8 @@
}
// For testing
- Upload(UploadedFile value, FieldValidator<Object> validate, MultipartDecoder decoder,
- ValidationTracker tracker, ComponentResources resources)
+ Upload(UploadedFile value, FieldValidator<Object> validate, MultipartDecoder decoder, ValidationTracker tracker,
+ ComponentResources resources)
{
_value = value;
if (validate != null) _validate = validate;
@@ -100,6 +97,7 @@
_resources = resources;
}
+ @SuppressWarnings({"unchecked"})
@Override
protected void processSubmission(FormSupport formSupport, String elementName)
{
@@ -107,13 +105,14 @@
if (uploaded != null)
{
- if (uploaded.getFileName() == null || uploaded.getFileName().length() == 0)
- uploaded = null;
+ if (uploaded.getFileName() == null || uploaded.getFileName().length() == 0) uploaded = null;
}
+ FieldValidator wrappedValidator = new ComponentValidatorWrapper(_resources, _validate);
+
try
{
- _validate.validate(uploaded);
+ wrappedValidator.validate(uploaded);
}
catch (ValidationException ex)
{