tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hls...@apache.org
Subject svn commit: r493530 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/corelib/base/ main/java/org/apache/tapestry/corelib/components/ main/java/org/...
Date Sat, 06 Jan 2007 18:28:26 GMT
Author: hlship
Date: Sat Jan  6 10:28:24 2007
New Revision: 493530

URL: http://svn.apache.org/viewvc?view=rev&rev=493530
Log:
Add basic decoration of form labels and form fields.

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BaseValidationDecorator.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationDecorator.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/DefaultValidationDelegateCommand.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ValidationTrackerImplTest.java
      - copied, changed from r492704, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationTrackerImplTest.java
Removed:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationTrackerImplTest.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Environmental.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Errors.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Label.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/RenderQueue.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Environment.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css
    tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/EnvironmentImplTest.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/validator/RequiredTest.java

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BaseValidationDecorator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BaseValidationDecorator.java?view=auto&rev=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BaseValidationDecorator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/BaseValidationDecorator.java Sat Jan  6 10:28:24 2007
@@ -0,0 +1,42 @@
+// 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;
+
+import org.apache.tapestry.dom.Element;
+
+/**
+ * Base implementation of {@link ValidationDecorator} that does nothing. Subclasses may override
+ * specific methods, knowing that all other methods do nothing at all.
+ */
+public abstract class BaseValidationDecorator implements ValidationDecorator
+{
+
+    public void afterField(Field field)
+    {
+    }
+
+    public void beforeField(Field field)
+    {
+    }
+
+    public void insideField(Field field)
+    {
+    }
+
+    public void insideLabel(Field field, Element labelElement)
+    {
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/MarkupWriter.java Sat Jan  6 10:28:24 2007
@@ -107,4 +107,7 @@
 
     /** Returns the Document into which this writer creates elements or other nodes. */
     Document getDocument();
+
+    /** Returns the currently active element. */
+    Element getElement();
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationDecorator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationDecorator.java?view=auto&rev=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationDecorator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationDecorator.java Sat Jan  6 10:28:24 2007
@@ -0,0 +1,53 @@
+// 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;
+
+import org.apache.tapestry.dom.Element;
+
+/**
+ * An object responsible for performing decorations around fields and field labels. The decorator is
+ * notified at intervals by the fields and labels.
+ */
+public interface ValidationDecorator
+{
+    /**
+     * Invoked after the label has rendered its tag, but before it has rendered content inside the
+     * tag, to allow the decorator to write additional attributes.
+     * 
+     * @param field
+     *            the field corresponding to the label
+     * @param labelElement
+     *            the element for this label
+     */
+    void insideLabel(Field field, Element labelElement);
+
+    /**
+     * Renders immediately before the field itself. The field will typically render a single
+     * element, though a complex field may render multiple elements or even some JavaScript.
+     * 
+     * @param field
+     */
+    void beforeField(Field field);
+
+    /**
+     * Invoked at a point where the decorator may write additional attributes into the field.
+     * 
+     * @param field
+     */
+    void insideField(Field field);
+
+    /** Invoked after the field has completed rendering itself. */
+    void afterField(Field field);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Environmental.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Environmental.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Environmental.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/annotations/Environmental.java Sat Jan  6 10:28:24 2007
@@ -12,26 +12,28 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import org.apache.tapestry.services.Environment;
-
-/**
- * Defines a field that is replaced at runtime with a read-only value obtained from the
- * {@link Environment} service.
- * 
- * 
- */
-@Target(FIELD)
-@Documented
-@Retention(RUNTIME)
-public @interface Environmental {
-
-}
+package org.apache.tapestry.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.apache.tapestry.services.Environment;
+
+/**
+ * Defines a field that is replaced at runtime with a read-only value obtained from the
+ * {@link Environment} service.
+ */
+@Target(FIELD)
+@Documented
+@Retention(RUNTIME)
+public @interface Environmental {
+    /**
+     * The value determines if the environmental service to be injected is required or not. In most
+     * cases, it is, so the default is true.
+     */
+    boolean value() default true;
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractField.java Sat Jan  6 10:28:24 2007
@@ -20,7 +20,11 @@
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.Field;
 import org.apache.tapestry.FieldValidator;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.ValidationDecorator;
 import org.apache.tapestry.ValidationException;
+import org.apache.tapestry.annotations.AfterRender;
+import org.apache.tapestry.annotations.BeginRender;
 import org.apache.tapestry.annotations.ComponentClass;
 import org.apache.tapestry.annotations.Environmental;
 import org.apache.tapestry.annotations.Inject;
@@ -70,6 +74,9 @@
     @Mixin
     private DiscardBody _discardBody;
 
+    @Environmental
+    private ValidationDecorator _decorator;
+
     protected static final FieldValidator NOOP_VALIDATOR = new FieldValidator()
     {
         public void check(Object value) throws ValidationException
@@ -234,4 +241,21 @@
      *            the name of the element (used to find the correct parameter in the request)
      */
     protected abstract void processSubmission(FormParameterLookup paramLookup, String elementName);
+
+    @BeginRender
+    final void beforeDecorator(MarkupWriter writer)
+    {
+        _decorator.beforeField(this);
+    }
+
+    @AfterRender
+    final void afterDecorat(MarkupWriter writer)
+    {
+        _decorator.afterField(this);
+    }
+
+    protected final ValidationDecorator getValidationDecorator()
+    {
+        return _decorator;
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/base/AbstractTextField.java Sat Jan  6 10:28:24 2007
@@ -101,6 +101,8 @@
             value = _translate.toClient(_value);
 
         writeFieldTag(writer, value);
+
+        getValidationDecorator().insideField(this);
     }
 
     /**

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Errors.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Errors.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Errors.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Errors.java Sat Jan  6 10:28:24 2007
@@ -32,7 +32,8 @@
     @Parameter
     private String _class = "tapestry-error";
 
-    @Environmental
+    // Allow null so we can generate a better error message if missing
+    @Environmental(false)
     private ValidationTracker _tracker;
 
     void beginRender(MarkupWriter writer)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Form.java Sat Jan  6 10:28:24 2007
@@ -46,6 +46,7 @@
 import org.apache.tapestry.services.ComponentSource;
 import org.apache.tapestry.services.Environment;
 import org.apache.tapestry.services.FormSupport;
+import org.apache.tapestry.services.Heartbeat;
 import org.apache.tapestry.services.PageRenderSupport;
 
 /**
@@ -126,6 +127,9 @@
     @Environmental
     private PageRenderSupport _pageRenderSupport;
 
+    @Environmental
+    private Heartbeat _heartbeat;
+
     @Inject("service:tapestry.internal.FormParameterLookup")
     private FormParameterLookup _paramLookup;
 
@@ -213,11 +217,15 @@
 
         writer.end(); // div
 
+        _heartbeat.begin();
+
     }
 
     @AfterRender
     void after(MarkupWriter writer)
     {
+        _heartbeat.end();
+
         writer.end(); // form
 
         // Now, inject into the div the remaining hidden field (the list of actions).

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Label.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Label.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Label.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/corelib/components/Label.java Sat Jan  6 10:28:24 2007
@@ -16,6 +16,7 @@
 
 import org.apache.tapestry.Field;
 import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.ValidationDecorator;
 import org.apache.tapestry.annotations.AfterRender;
 import org.apache.tapestry.annotations.BeforeRenderBody;
 import org.apache.tapestry.annotations.BeginRender;
@@ -36,17 +37,26 @@
     @Environmental
     private Heartbeat _heartbeat;
 
+    @Environmental
+    private ValidationDecorator _decorator;
+
     @BeginRender
     void begin(MarkupWriter writer)
     {
         final Field field = _field;
+
         final Element element = writer.element("label");
 
+        // Uh oh!  Referenching a private field (that happens to get instrumented up the wazoo) from
+        // a inner class causes a java.lang.Verify error (Unable to pop operand off an empty stack).
+        // Perhaps this is a Javassist error?  Shouldn't the inner class be going through a synthetic
+        // accessor method of some kind?
+        
+        final ValidationDecorator decorator = _decorator;
+
         // Since we don't know if the field has rendered yet, we need to defer writing the for
-        // attribute until
-        // we know the field has rendered (and set its clientId property). That's exactly what
-        // Heartbeat
-        // is for.
+        // attribute until we know the field has rendered (and set its clientId property). That's
+        // exactly what Heartbeat is for.
 
         Runnable command = new Runnable()
         {
@@ -54,11 +64,9 @@
             {
                 String fieldId = field.getClientId();
 
-                // TODO: What if "for" was an informal parameter? We need to override that here,
-                // which involves a change
-                // to the Element API.
+                element.forceAttributes("for", fieldId);
 
-                element.attribute("for", fieldId);
+                decorator.insideLabel(field, element);
             }
         };
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/dom/Element.java Sat Jan  6 10:28:24 2007
@@ -117,6 +117,32 @@
     }
 
     /**
+     * Forces changes to a number of attributes. The new attributes <em>overwrite</em> previous
+     * values.
+     */
+    public void forceAttributes(String... namesAndValues)
+    {
+        if (_attributes == null)
+            _attributes = newMap();
+
+        int i = 0;
+
+        while (i < namesAndValues.length)
+        {
+            String name = namesAndValues[i++];
+            String value = namesAndValues[i++];
+
+            if (value == null)
+            {
+                _attributes.remove(name);
+                continue;
+            }
+
+            _attributes.put(name, value);
+        }
+    }
+
+    /**
      * Creates and returns a new Element node as a child of this node.
      * 
      * @param name

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java?view=auto&rev=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java Sat Jan  6 10:28:24 2007
@@ -0,0 +1,80 @@
+// 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.internal;
+
+import org.apache.tapestry.BaseValidationDecorator;
+import org.apache.tapestry.Field;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.ValidationTracker;
+import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.services.Environment;
+
+/**
+ * Default implementation that writes an attribute into fields or labels that are in error.
+ */
+public final class DefaultValidationDecorator extends BaseValidationDecorator
+{
+    private final Environment _environment;
+
+    private static final String ERROR_CLASS = "tapestry-error";
+
+    public DefaultValidationDecorator(final Environment environment)
+    {
+        _environment = environment;
+    }
+
+    @Override
+    public void insideField(Field field)
+    {
+        if (inError(field))
+            addErrorClassToCurrentElement();
+    }
+
+    @Override
+    public void insideLabel(Field field, Element element)
+    {
+        if (field == null)
+            return;
+
+        if (inError(field))
+            addErrorClass(element);
+    }
+
+    private boolean inError(Field field)
+    {
+        ValidationTracker tracker = _environment.peekRequired(ValidationTracker.class);
+
+        return tracker.inError(field);
+    }
+
+    private void addErrorClassToCurrentElement()
+    {
+        MarkupWriter writer = _environment.peekRequired(MarkupWriter.class);
+
+        Element element = writer.getElement();
+
+        addErrorClass(element);
+    }
+
+    private void addErrorClass(Element element)
+    {
+        String current = element.getAttribute("class");
+
+        String newValue = current == null ? ERROR_CLASS : current + " " + ERROR_CLASS;
+
+        element.forceAttributes("class", newValue);
+    }
+
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java?view=auto&rev=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java Sat Jan  6 10:28:24 2007
@@ -0,0 +1,148 @@
+// 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.internal;
+
+import org.apache.tapestry.Field;
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.ValidationDecorator;
+import org.apache.tapestry.ValidationTracker;
+import org.apache.tapestry.dom.Element;
+import org.apache.tapestry.dom.XMLMarkupModel;
+import org.apache.tapestry.internal.services.MarkupWriterImpl;
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.test.TapestryTestCase;
+import org.testng.annotations.Test;
+
+public class DefaultValidationDecoratorTest extends TapestryTestCase
+{
+    @Test
+    public void label_has_no_field()
+    {
+        Environment env = newEnvironment();
+
+        replay();
+
+        ValidationDecorator decorator = new DefaultValidationDecorator(env);
+
+        decorator.insideLabel(null, null);
+
+        verify();
+    }
+
+    @Test
+    public void label_error_no_existing_class_attribute()
+    {
+        MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
+        Environment env = newEnvironment();
+        Field field = newField();
+        ValidationTracker tracker = newValidationTracker();
+
+        train_peekRequired(env, ValidationTracker.class, tracker);
+        train_inError(tracker, field, true);
+
+        replay();
+
+        Element e = writer.element("label", "accesskey", "f");
+
+        ValidationDecorator decorator = new DefaultValidationDecorator(env);
+
+        decorator.insideLabel(field, e);
+
+        assertEquals(writer.toString(), "<label accesskey=\"f\" class=\"tapestry-error\"/>");
+
+        verify();
+    }
+
+    @Test
+    public void label_error_with_existing_class_attribute()
+    {
+        MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
+        Environment env = newEnvironment();
+        Field field = newField();
+        ValidationTracker tracker = newValidationTracker();
+
+        train_peekRequired(env, ValidationTracker.class, tracker);
+        train_inError(tracker, field, true);
+
+        replay();
+
+        Element e = writer.element("label", "accesskey", "f", "class", "foo");
+
+        ValidationDecorator decorator = new DefaultValidationDecorator(env);
+
+        decorator.insideLabel(field, e);
+
+        assertEquals(writer.toString(), "<label accesskey=\"f\" class=\"foo tapestry-error\"/>");
+
+        verify();
+    }
+
+    @Test
+    public void field_error()
+    {
+        MarkupWriter writer = new MarkupWriterImpl(new XMLMarkupModel(), null);
+        Environment env = newEnvironment();
+        Field field = newField();
+        ValidationTracker tracker = newValidationTracker();
+
+        train_peekRequired(env, ValidationTracker.class, tracker);
+        train_inError(tracker, field, true);
+        train_peekRequired(env, MarkupWriter.class, writer);
+
+        replay();
+
+        writer.element(
+                "input",
+                "type",
+                "text",
+                "name",
+                "ex",
+                "class",
+                "foo",
+                "value",
+                "freddy",
+                "size",
+                "30");
+
+        ValidationDecorator decorator = new DefaultValidationDecorator(env);
+
+        decorator.insideField(field);
+
+        assertEquals(
+                writer.toString(),
+                "<input class=\"foo tapestry-error\" name=\"ex\" size=\"30\" type=\"text\" value=\"freddy\"/>");
+
+        verify();
+    }
+
+    @Test
+    public void field_ok()
+    {
+        Environment env = newEnvironment();
+        Field field = newField();
+        ValidationTracker tracker = newValidationTracker();
+
+        train_peekRequired(env, ValidationTracker.class, tracker);
+        train_inError(tracker, field, false);
+
+        replay();
+
+        ValidationDecorator decorator = new DefaultValidationDecorator(env);
+
+        decorator.insideField(field);
+
+        verify();
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/DefaultValidationDelegateCommand.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/DefaultValidationDelegateCommand.java?view=auto&rev=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/DefaultValidationDelegateCommand.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/DefaultValidationDelegateCommand.java Sat Jan  6 10:28:24 2007
@@ -0,0 +1,40 @@
+// 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.internal.services;
+
+import org.apache.tapestry.ValidationDecorator;
+import org.apache.tapestry.internal.DefaultValidationDecorator;
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.services.PageRenderCommand;
+
+/**
+ * Pushes a {@link DefaultValidationDecorator} instance into the Environment's
+ * {@link ValidationDecorator} service stack.
+ */
+public class DefaultValidationDelegateCommand implements PageRenderCommand
+{
+    public void cleanup(Environment environment)
+    {
+        environment.pop(ValidationDecorator.class);
+    }
+
+    public void setup(Environment environment)
+    {
+        ValidationDecorator decorator = new DefaultValidationDecorator(environment);
+
+        environment.push(ValidationDecorator.class, decorator);
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentImpl.java Sat Jan  6 10:28:24 2007
@@ -18,8 +18,10 @@
 import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
 
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry.services.Environment;
 
 /**
@@ -51,6 +53,27 @@
         LinkedList<T> stack = stackFor(type);
 
         return stack.isEmpty() ? null : stack.getFirst();
+    }
+
+    public <T> T peekRequired(Class<T> type)
+    {
+        T result = peek(type);
+
+        if (result == null)
+        {
+            List<Class> types = CollectionFactory.newList();
+            for (Map.Entry<Class, LinkedList> e : _stacks.entrySet())
+            {
+                LinkedList list = e.getValue();
+
+                if (list != null && !list.isEmpty())
+                    types.add(e.getKey());
+            }
+
+            throw new RuntimeException(ServicesMessages.missingFromEnvironment(type, types));
+        }
+
+        return result;
     }
 
     public <T> T pop(Class<T> type)

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EnvironmentalWorker.java Sat Jan  6 10:28:24 2007
@@ -12,78 +12,77 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
-import java.lang.reflect.Modifier;
-import java.util.List;
-
-import org.apache.tapestry.annotations.Environmental;
+package org.apache.tapestry.internal.services;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import org.apache.tapestry.annotations.Environmental;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
-import org.apache.tapestry.model.MutableComponentModel;
-import org.apache.tapestry.services.ClassTransformation;
-import org.apache.tapestry.services.ComponentClassTransformWorker;
-import org.apache.tapestry.services.Environment;
-import org.apache.tapestry.services.MethodSignature;
-
-/**
- * Obtains a value from the {@link Environment} service based on the field type. This is triggered
- * by the presense of the {@link Environmental} annotation.
- * 
- * 
- */
-public class EnvironmentalWorker implements ComponentClassTransformWorker
-{
-    private final Environment _environment;
-
-    public EnvironmentalWorker(Environment environment)
-    {
-        _environment = environment;
-    }
-
-    public void transform(ClassTransformation transformation, MutableComponentModel model)
-    {
-        List<String> names = transformation.findFieldsWithAnnotation(Environmental.class);
-
-        if (names.isEmpty())
-            return;
-
-        // TODO: addInjectField should be smart about if the field has already been injected (with
-        // the same type)
-        // for this transformation, or the parent transformation.
-
-        String envField = transformation.addInjectedField(
-                Environment.class,
-                "environment",
-                _environment);
-
-        for (String name : names)
-        {
-            Environmental annotation = transformation.getFieldAnnotation(name, Environmental.class);
-
-            String type = transformation.getFieldType(name);
-
-            // TODO: Check for primitives
-
-            // Caching might be good for efficiency at some point.
-
-            String methodName = transformation.newMemberName("_environment_read_"
-                    + InternalUtils.stripMemberPrefix(name));
-
-            MethodSignature sig = new MethodSignature(Modifier.PRIVATE, type, methodName, null,
-                    null);
-
-            // TODO: Check for null
-
-            String body = String.format("return ($r) %s.peek($type);", envField);
-
-            transformation.addMethod(sig, body);
-
-            transformation.replaceReadAccess(name, methodName);
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.services.MethodSignature;
+
+/**
+ * Obtains a value from the {@link Environment} service based on the field type. This is triggered
+ * by the presense of the {@link Environmental} annotation.
+ */
+public class EnvironmentalWorker implements ComponentClassTransformWorker
+{
+    private final Environment _environment;
+
+    public EnvironmentalWorker(Environment environment)
+    {
+        _environment = environment;
+    }
+
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        List<String> names = transformation.findFieldsWithAnnotation(Environmental.class);
+
+        if (names.isEmpty())
+            return;
+
+        // TODO: addInjectField should be smart about if the field has already been injected (with
+        // the same type)
+        // for this transformation, or the parent transformation.
+
+        String envField = transformation.addInjectedField(
+                Environment.class,
+                "environment",
+                _environment);
+
+        for (String name : names)
+        {
+            Environmental annotation = transformation.getFieldAnnotation(name, Environmental.class);
+
+            String type = transformation.getFieldType(name);
+
+            // TODO: Check for primitives
+
+            // Caching might be good for efficiency at some point.
+
+            String methodName = transformation.newMemberName("environment_read_"
+                    + InternalUtils.stripMemberPrefix(name));
+
+            MethodSignature sig = new MethodSignature(Modifier.PRIVATE, type, methodName, null,
+                    null);
+
+            String body = String.format(
+                    "return ($r) %s.%s($type);",
+                    envField,
+                    annotation.value() ? "peekRequired" : "peek");
+
+            transformation.addMethod(sig, body);
+
+            transformation.replaceReadAccess(name, methodName);
             transformation.makeReadOnly(name);
-            transformation.removeField(name);
-
-            transformation.claimField(name, annotation);
-        }
-    }
-
-}
+            transformation.removeField(name);
+
+            transformation.claimField(name, annotation);
+        }
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/MarkupWriterImpl.java Sat Jan  6 10:28:24 2007
@@ -65,6 +65,11 @@
         return _document;
     }
 
+    public Element getElement()
+    {
+        return _current;
+    }
+
     public void write(String text)
     {
         ensureCurrentElement();

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java Sat Jan  6 10:28:24 2007
@@ -15,7 +15,6 @@
 package org.apache.tapestry.internal.services;
 
 import org.apache.tapestry.MarkupWriter;
-import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.internal.structure.Page;
 import org.apache.tapestry.services.PageRenderInitializer;
 
@@ -30,9 +29,7 @@
 
     public void renderPageMarkup(Page page, MarkupWriter writer)
     {
-        Document document = writer.getDocument();
-
-        _pageRenderInitializer.setup(document);
+        _pageRenderInitializer.setup(writer);
 
         RenderQueueImpl queue = new RenderQueueImpl(page.getLog());
 
@@ -42,7 +39,7 @@
 
         queue.run(writer);
 
-        _pageRenderInitializer.cleanup(document);
+        _pageRenderInitializer.cleanup(writer);
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ServicesMessages.java Sat Jan  6 10:28:24 2007
@@ -23,6 +23,7 @@
 import org.apache.tapestry.ioc.Location;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry.ioc.internal.util.InternalUtils;
 import org.apache.tapestry.ioc.internal.util.MessagesImpl;
 import org.apache.tapestry.runtime.Component;
@@ -302,5 +303,17 @@
     static String mixinsInvalidWithoutIdOrType(String elementName)
     {
         return MESSAGES.format("mixins-invalid-without-id-or-type", elementName);
+    }
+
+    static String missingFromEnvironment(Class type, Collection<Class> availableTypes)
+    {
+        List<String> types = CollectionFactory.newList();
+
+        for (Class c : availableTypes)
+            types.add(c.getName());
+
+        return MESSAGES.format("missing-from-environment", type.getName(), InternalUtils
+                .joinSorted(types));
+
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/RenderQueue.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/RenderQueue.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/RenderQueue.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/RenderQueue.java Sat Jan  6 10:28:24 2007
@@ -12,16 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.runtime;
-
-/**
- * A stateful object that manages the process of rendering a page. Rending a page in Tapestry is
- * based on a command queue.
- * 
- * 
- */
-public interface RenderQueue
-{
-    /** Adds the new command to the front of the queue. */
-    void push(RenderCommand command);
-}
+package org.apache.tapestry.runtime;
+
+/**
+ * A stateful object that manages the process of rendering a page. Rending a page in Tapestry is
+ * based on a command queue.
+ */
+public interface RenderQueue
+{
+    /** Adds the new command to the front of the queue. */
+    void push(RenderCommand command);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Environment.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Environment.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Environment.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/Environment.java Sat Jan  6 10:28:24 2007
@@ -12,54 +12,63 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.services;
-
-/**
- * Provides access to environment services, which are almost always provided to enclosed components
- * by enclosing components.
- * <p>
- * The Environment acts like a collection of stacks. Each stack contains environmental service
- * providers of a given type.
- * 
- * 
- */
-public interface Environment
-{
-    /**
-     * @param <T>
-     *            the type of environmental service
-     * @param type
-     *            class used to select a service
-     * @return the current service of that type, or null if no service of that type has been added
-     */
-    <T> T peek(Class<T> type);
-
-    /**
-     * Removes and returns the top environmental service of the selected type.
-     * 
-     * @param <T>
-     * @param type
-     * @return
-     * @throws NoSuchElementException
-     *             if the environmental stack (for the specified type) is empty
-     */
-    <T> T pop(Class<T> type);
-
-    /**
-     * Pushes a new service onto the stack. The old service at the top of the stack is returned (it
-     * may be null).
-     * 
-     * @param <T>
-     * @param type
-     *            the type of service to store
-     * @param instance
-     *            the service instance
-     * @return the previous top service
-     */
-    <T> T push(Class<T> type, T instance);
-
-    /**
-     * Clears all stacks; used when initializing the Environment before a render.
-     */
-    void clear();
-}
+package org.apache.tapestry.services;
+
+/**
+ * Provides access to environment services, which are almost always provided to enclosed components
+ * by enclosing components.
+ * <p>
+ * The Environment acts like a collection of stacks. Each stack contains environmental service
+ * providers of a given type.
+ */
+public interface Environment
+{
+    /**
+     * @param <T>
+     *            the type of environmental service
+     * @param type
+     *            class used to select a service
+     * @return the current service of that type, or null if no service of that type has been added
+     */
+    <T> T peek(Class<T> type);
+
+    /**
+     * @param <T>
+     *            the type of environmental service
+     * @param type
+     *            class used to select a service
+     * @return the current service
+     * @throws RuntimeException
+     *             if no service of that type has been added
+     */
+    <T> T peekRequired(Class<T> type);
+
+    /**
+     * Removes and returns the top environmental service of the selected type.
+     * 
+     * @param <T>
+     * @param type
+     * @return
+     * @throws NoSuchElementException
+     *             if the environmental stack (for the specified type) is empty
+     */
+    <T> T pop(Class<T> type);
+
+    /**
+     * Pushes a new service onto the stack. The old service at the top of the stack is returned (it
+     * may be null).
+     * 
+     * @param <T>
+     * @param type
+     *            the type of service to store
+     * @param instance
+     *            the service instance
+     * @return the previous top service
+     */
+    <T> T push(Class<T> type, T instance);
+
+    /**
+     * Clears all stacks; used when initializing the Environment before a render.
+     */
+    void clear();
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderCommand.java Sat Jan  6 10:28:24 2007
@@ -14,9 +14,16 @@
 
 package org.apache.tapestry.services;
 
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.dom.Document;
+
 /**
  * Page render commands are invoked at the start of the page render cycle and at the end. This
  * allows them to perform initial startup or final cleanup (or both).
+ * <p>
+ * When commands are invoked (by the default {@link PageRenderInitializer}), the
+ * {@link MarkupWriter} and {@link Document} will have already been set. Most commands deal with
+ * storing new environmental services into the Environment.
  * 
  * @see PageRenderInitializer
  */

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java Sat Jan  6 10:28:24 2007
@@ -14,7 +14,7 @@
 
 package org.apache.tapestry.services;
 
-import org.apache.tapestry.dom.Document;
+import org.apache.tapestry.MarkupWriter;
 
 /**
  * Responsible for setup and cleanup of the rendering of a page. The implementation of this is based
@@ -23,21 +23,20 @@
 public interface PageRenderInitializer
 {
     /**
-     * Perform any initial setup, by invoking {@link PageRenderCommand#setup(Environment, Document)}.
+     * Perform any initial setup, by invoking {@link PageRenderCommand#setup(Environment)}.
      * Execution occurs in normal order.
      * 
-     * @param document
-     *            the document (initially empty) that will be constructed from the page and its
-     *            components
+     * @param writer
+     *            the markup writer that will be used to generate all output markup
      */
-    void setup(Document document);
+    void setup(MarkupWriter writer);
 
     /**
-     * Peform any post-render cleanup, by invoking {@link PageRenderCommand#cleanup(Environment, Document)}.
+     * Peform any post-render cleanup, by invoking {@link PageRenderCommand#cleanup(Environment)}.
      * Execution order is reversed.
      * 
-     * @param document
-     *            the populated document, prior to being streamed to the client
+     * @param writer
+     *            the markup writer used to generate all output markup in the document
      */
-    void cleanup(Document document);
+    void cleanup(MarkupWriter writer);
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java Sat Jan  6 10:28:24 2007
@@ -67,6 +67,7 @@
 import org.apache.tapestry.internal.services.ComponentWorker;
 import org.apache.tapestry.internal.services.ContextImpl;
 import org.apache.tapestry.internal.services.DefaultInjectionProvider;
+import org.apache.tapestry.internal.services.DefaultValidationDelegateCommand;
 import org.apache.tapestry.internal.services.EnvironmentImpl;
 import org.apache.tapestry.internal.services.EnvironmentalWorker;
 import org.apache.tapestry.internal.services.FieldValidatorSourceImpl;
@@ -717,17 +718,18 @@
     {
         return new PageRenderInitializer()
         {
-            public void setup(Document document)
+            public void setup(MarkupWriter writer)
             {
                 _environment.clear();
 
-                _environment.push(Document.class, document);
+                _environment.push(MarkupWriter.class, writer);
+                _environment.push(Document.class, writer.getDocument());
 
                 for (PageRenderCommand command : configuration)
                     command.setup(_environment);
             }
 
-            public void cleanup(Document document)
+            public void cleanup(MarkupWriter writer)
             {
                 Iterator<PageRenderCommand> i = InternalUtils.reverseIterator(configuration);
 
@@ -777,6 +779,7 @@
 
         configuration.add("InjectStandardStylesheet", new InjectStandardStylesheetCommand(
                 threadLocale, assetSource));
+        configuration.add("DefaultValidationDelegate", new DefaultValidationDelegateCommand());
     }
 
     /** A public service since extensions may provide new persistent strategies. */

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java Sat Jan  6 10:28:24 2007
@@ -35,12 +35,16 @@
 import org.apache.tapestry.Asset;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.ComponentResourcesCommon;
+import org.apache.tapestry.Field;
 import org.apache.tapestry.FieldValidator;
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.Translator;
+import org.apache.tapestry.ValidationDecorator;
+import org.apache.tapestry.ValidationTracker;
 import org.apache.tapestry.Validator;
 import org.apache.tapestry.annotations.Inject;
 import org.apache.tapestry.annotations.Parameter;
+import org.apache.tapestry.internal.DefaultValidationDecorator;
 import org.apache.tapestry.ioc.Location;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.ioc.Resource;
@@ -72,6 +76,7 @@
 import org.apache.tapestry.services.ValidationMessagesSource;
 import org.easymock.EasyMock;
 import org.easymock.IAnswer;
+import org.testng.annotations.Test;
 
 /**
  * Base test case that adds a number of convienience factory and training methods for the public
@@ -585,6 +590,11 @@
         expect(env.peek(type)).andReturn(value);
     }
 
+    protected final <T> void train_peekRequired(Environment env, Class<T> type, T value)
+    {
+        expect(env.peekRequired(type)).andReturn(value);
+    }
+
     protected final Environment newEnvironment()
     {
         return newMock(Environment.class);
@@ -598,5 +608,39 @@
     protected final Translator newTranslator()
     {
         return newMock(Translator.class);
+    }
+
+    @Test
+    public void label_when_field_not_in_error()
+    {
+        Environment env = newEnvironment();
+        Field field = newField();
+        ValidationTracker tracker = newValidationTracker();
+    
+        train_peekRequired(env, ValidationTracker.class, tracker);
+        train_inError(tracker, field, false);
+    
+        replay();
+    
+        ValidationDecorator decorator = new DefaultValidationDecorator(env);
+    
+        decorator.insideLabel(field, null);
+    
+        verify();
+    }
+
+    protected final ValidationTracker newValidationTracker()
+    {
+        return newMock(ValidationTracker.class);
+    }
+
+    protected final Field newField()
+    {
+        return newMock(Field.class);
+    }
+
+    protected final void train_inError(ValidationTracker tracker, Field field, boolean inError)
+    {
+        expect(tracker.inError(field)).andReturn(inError);
     }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/default.css Sat Jan  6 10:28:24 2007
@@ -23,8 +23,17 @@
 DIV.tapestry-error LI {
     margin-left: -20px;
 }
+DIV.invisible {
+    display: none;
+}
 
+LABEL.tapestry-error
+{
+  color:red;
+}
 
-DIV.invisible {
-  display: none;
+INPUT.tapestry-error, TEXTAREA.tapestry-error
+{
+  background-color: red;
+  color: white;
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/resources/org/apache/tapestry/internal/services/ServicesStrings.properties Sat Jan  6 10:28:24 2007
@@ -68,4 +68,5 @@
 unknown-validator-type=Unknown validator type '%s'.  Configured validators are %s.
 validator-specification-parse-error=Unexpected character '%s' at position %d of input string: %s
 unexpected-tapestry-attribute=Attribute '%s' is not defined in the Tapestry template schema.
-unknown-translator-type=Unknown translator type '%s'.  Configured translators are %s.
\ No newline at end of file
+unknown-translator-type=Unknown translator type '%s'.  Configured translators are %s.
+missing-from-environment=No object of type %s is available from the Environment.  Available types are %s.
\ No newline at end of file

Copied: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ValidationTrackerImplTest.java (from r492704, tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationTrackerImplTest.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ValidationTrackerImplTest.java?view=diff&rev=493530&p1=tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationTrackerImplTest.java&r1=492704&p2=tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ValidationTrackerImplTest.java&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/ValidationTrackerImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/ValidationTrackerImplTest.java Sat Jan  6 10:28:24 2007
@@ -1,4 +1,4 @@
-// Copyright 2006 The Apache Software Foundation
+// Copyright 2006, 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.
@@ -190,11 +190,6 @@
         expect(field.getElementName()).andReturn(elementName).atLeastOnce();
 
         return field;
-    }
-
-    protected final Field newField()
-    {
-        return newMock(Field.class);
     }
 
     @SuppressWarnings("unchecked")

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java Sat Jan  6 10:28:24 2007
@@ -325,4 +325,20 @@
                 d.toString(),
                 "<fred><start/><one><tiny/></one><two><bubbles/></two><end/></fred>");
     }
+
+    @Test
+    public void force_attributes_overrides_existing()
+    {
+        Document d = new Document(new XMLMarkupModel());
+
+        Element root = d.newRootElement("fred");
+
+        root.attributes("hi", "ho", "gnip", "gnop");
+
+        assertEquals(root.toString(), "<fred gnip=\"gnop\" hi=\"ho\"/>");
+
+        root.forceAttributes("hi", "bit", "gnip", null);
+
+        assertEquals(root.toString(), "<fred hi=\"bit\"/>");
+    }
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/IntegrationTests.java Sat Jan  6 10:28:24 2007
@@ -422,10 +422,26 @@
         assertTextPresent("You must provide a value for Email.");
         assertTextPresent("You must provide a value for Incident Message.");
 
+        // Check on decorations via the default validation decorator:
+
+        assertText("//label[1]/@class", "tapestry-error");
+        assertText("//label[2]/@class", "tapestry-error");
+        assertText("//input[@id='email']/@class", "tapestry-error");
+        assertText("//textarea[@id='message']/@class", "tapestry-error");
+
         _selenium.type("email", "foo@bar.baz");
         _selenium.type("message", "Show me the money!");
 
         clickAndWait("//input[@type='submit']");
+
+        // Make sure the decoration went away.
+
+        // Sorry, not sure how to do that, since the attributes don't exist, we get xpath errors.
+
+        // assertText("//label[1]/@class", "");
+        // assertText("//label[2]/@class", "");
+        // assertText("//input[@id='email']/@class", "");
+        // assertText("//textarea[@id='message']/@class", "");
 
         assertTextPresent("[foo@bar.baz]");
         assertTextPresent("[Show me the money!]");

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/EnvironmentImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/EnvironmentImplTest.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/EnvironmentImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/EnvironmentImplTest.java Sat Jan  6 10:28:24 2007
@@ -12,83 +12,128 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal.services;
-
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import org.apache.tapestry.services.Environment;
-import org.apache.tapestry.test.TapestryTestCase;
-import org.testng.annotations.Test;
-
-/**
- * 
- */
-public class EnvironmentImplTest extends TapestryTestCase
-{
-    @Test
-    public void peek_when_empty_returns_null()
-    {
-        Environment e = new EnvironmentImpl();
-
-        assertNull(e.peek(Runnable.class));
-        assertNull(e.peek(Map.class));
-    }
-
-    @Test
-    public void push_and_pop()
-    {
-        Environment e = new EnvironmentImpl();
-        Runnable r1 = newRunnable();
-        Runnable r2 = newRunnable();
-
-        replay();
-
-        assertNull(e.push(Runnable.class, r1));
-
-        assertSame(r1, e.peek(Runnable.class));
-
-        assertSame(r1, e.push(Runnable.class, r2));
-
-        assertSame(r2, e.peek(Runnable.class));
-
-        assertSame(r2, e.pop(Runnable.class));
-        assertSame(r1, e.pop(Runnable.class));
-
-        verify();
-    }
-
-    @Test
-    public void clear()
-    {
-        Environment e = new EnvironmentImpl();
-        Runnable r1 = newRunnable();
-        Runnable r2 = newRunnable();
-
-        replay();
-
-        e.push(Runnable.class, r1);
-        e.push(Runnable.class, r2);
-
-        e.clear();
-
-        assertNull(e.peek(Runnable.class));
-
-        verify();
-    }
-
-    @Test
-    public void pop_when_empty_is_error()
-    {
-        Environment e = new EnvironmentImpl();
-
-        try
-        {
-            e.pop(Runnable.class);
-            unreachable();
-        }
-        catch (NoSuchElementException ex)
-        {
-        }
-    }
-}
+package org.apache.tapestry.internal.services;
+
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.tapestry.ioc.Location;
+import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.test.TapestryTestCase;
+import org.testng.annotations.Test;
+
+/**
+ * 
+ */
+public class EnvironmentImplTest extends TapestryTestCase
+{
+    @Test
+    public void peek_when_empty_returns_null()
+    {
+        Environment e = new EnvironmentImpl();
+
+        assertNull(e.peek(Runnable.class));
+        assertNull(e.peek(Map.class));
+    }
+
+    @Test
+    public void push_and_pop()
+    {
+        Environment e = new EnvironmentImpl();
+        Runnable r1 = newRunnable();
+        Runnable r2 = newRunnable();
+
+        replay();
+
+        assertNull(e.push(Runnable.class, r1));
+
+        assertSame(r1, e.peek(Runnable.class));
+
+        assertSame(r1, e.push(Runnable.class, r2));
+
+        assertSame(r2, e.peek(Runnable.class));
+
+        assertSame(r2, e.pop(Runnable.class));
+        assertSame(r1, e.pop(Runnable.class));
+
+        verify();
+    }
+
+    @Test
+    public void clear()
+    {
+        Environment e = new EnvironmentImpl();
+        Runnable r1 = newRunnable();
+        Runnable r2 = newRunnable();
+
+        replay();
+
+        e.push(Runnable.class, r1);
+        e.push(Runnable.class, r2);
+
+        e.clear();
+
+        assertNull(e.peek(Runnable.class));
+
+        verify();
+    }
+
+    @Test
+    public void pop_when_empty_is_error()
+    {
+        Environment e = new EnvironmentImpl();
+
+        try
+        {
+            e.pop(Runnable.class);
+            unreachable();
+        }
+        catch (NoSuchElementException ex)
+        {
+        }
+    }
+
+    @Test
+    public void peek_required_when_available()
+    {
+        Environment e = new EnvironmentImpl();
+        Location l = newLocation();
+
+        replay();
+
+        e.push(Location.class, l);
+
+        assertSame(l, e.peekRequired(Location.class));
+
+        verify();
+    }
+
+    @Test
+    public void peek_required_without_value_is_error()
+    {
+        Environment e = new EnvironmentImpl();
+        Location l = newLocation();
+        Component c = newComponent();
+
+        replay();
+
+        e.push(Location.class, l);
+        e.push(Component.class, c);
+
+        try
+        {
+            e.peekRequired(List.class);
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "No object of type java.util.List is available from the Environment.  Available types are org.apache.tapestry.ioc.Location, org.apache.tapestry.runtime.Component.");
+        }
+
+        verify();
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/validator/RequiredTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/validator/RequiredTest.java?view=diff&rev=493530&r1=493529&r2=493530
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/validator/RequiredTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/validator/RequiredTest.java Sat Jan  6 10:28:24 2007
@@ -94,9 +94,4 @@
 
         return field;
     }
-
-    protected final Field newField()
-    {
-        return newMock(Field.class);
-    }
 }



Mime
View raw message