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/26 06:36:21 UTC

svn commit: r598137 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/services/ test/java/org/apache/tapestry/internal/

Author: hlship
Date: Sun Nov 25 21:36:17 2007
New Revision: 598137

URL: http://svn.apache.org/viewvc?rev=598137&view=rev
Log:
TAPESTRY-1650: Ajax support (still in progress).
- Introduce MarkupRenderer and MarkupRendererFilter interfaces
- Convert PageRenderInitializer to organize the filters
- Convert the old PgaeRenderInitializer instances into MarkupRendererFilter instances
- Split partial page rendering (for Ajax) into its own service, PartialMarkupRenderer.


Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderInitializerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueue.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueueImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRenderer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRendererImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRenderer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRendererFilter.java
Removed:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/AjaxResponseGenerator.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/DefaultValidationDelegateCommand.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/DefaultPageRenderCommand.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PageRenderCommand.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/AjaxComponentActionRequestHandler.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ClassResultProcessor.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/DefaultValidationDecorator.java Sun Nov 25 21:36:17 2007
@@ -18,7 +18,6 @@
 import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.ioc.Messages;
 import org.apache.tapestry.services.Environment;
-import org.apache.tapestry.services.ValidationMessagesSource;
 
 /**
  * Default implementation that writes an attribute into fields or labels that are in error.
@@ -27,22 +26,26 @@
 {
     private final Environment _environment;
 
-    private Asset _iconAsset;
+    private final Asset _iconAsset;
 
-    private Messages _validationMessages;
+    private final Messages _validationMessages;
+
+    private final MarkupWriter _markupWriter;
 
     /**
      * @param environment        used to locate objects and services during the render
-     * @param validationMessages obtained from {@link ValidationMessagesSource}, used to obtain the label for the
+     * @param validationMessages obtained from {@link org.apache.tapestry.services.ValidationMessagesSource}, used to obtain the label for the
      *                           icon
      * @param iconAsset          asset for an icon that will be displayed after each field (marked with the
-     *                           "t-invisible" CSS class, if the field is not in error)
+     * @param markupWriter
      */
-    public DefaultValidationDecorator(final Environment environment, Messages validationMessages, Asset iconAsset)
+    public DefaultValidationDecorator(final Environment environment, Messages validationMessages, Asset iconAsset,
+                                      MarkupWriter markupWriter)
     {
         _environment = environment;
         _validationMessages = validationMessages;
         _iconAsset = iconAsset;
+        _markupWriter = markupWriter;
     }
 
     @Override
@@ -64,13 +67,18 @@
     {
         String iconId = field.getClientId() + ":icon";
 
-        MarkupWriter writer = _environment.peekRequired(MarkupWriter.class);
-
         String cssClass = inError(field) ? "t-error-icon" : "t-error-icon t-invisible";
 
-        writer.element("img", "src", _iconAsset.toClientURL(), "alt", _validationMessages
-                .get("icon-label"), "class", cssClass, "id", iconId);
-        writer.end();
+        _markupWriter.element("img",
+
+                              "src", _iconAsset.toClientURL(),
+
+                              "alt", _validationMessages.get("icon-label"),
+
+                              "class", cssClass,
+
+                              "id", iconId);
+        _markupWriter.end();
     }
 
     private boolean inError(Field field)
@@ -82,8 +90,7 @@
 
     private void addErrorClassToCurrentElement()
     {
-        MarkupWriter writer = _environment.peekRequired(MarkupWriter.class);
 
-        writer.getElement().addClassName(TapestryConstants.ERROR_CLASS);
+        _markupWriter.getElement().addClassName(TapestryConstants.ERROR_CLASS);
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/AjaxComponentActionRequestHandler.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/AjaxComponentActionRequestHandler.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/AjaxComponentActionRequestHandler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/AjaxComponentActionRequestHandler.java Sun Nov 25 21:36:17 2007
@@ -15,10 +15,14 @@
 package org.apache.tapestry.internal.services;
 
 import org.apache.tapestry.ComponentEventHandler;
+import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.TapestryConstants;
+import org.apache.tapestry.dom.Element;
 import org.apache.tapestry.internal.structure.ComponentPageElement;
 import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.internal.util.ContentType;
 import org.apache.tapestry.internal.util.Holder;
+import org.apache.tapestry.json.JSONObject;
 import org.apache.tapestry.runtime.Component;
 import org.apache.tapestry.runtime.RenderCommand;
 import org.apache.tapestry.services.ComponentActionRequestHandler;
@@ -38,12 +42,12 @@
 
     private final MarkupWriterFactory _factory;
 
-    private final PageMarkupRenderer _renderer;
+    private final PartialMarkupRenderer _renderer;
 
     private final Response _response;
 
     public AjaxComponentActionRequestHandler(RequestPageCache cache, MarkupWriterFactory factory,
-                                             PageMarkupRenderer renderer, Response response)
+                                             PartialMarkupRenderer renderer, Response response)
     {
         _cache = cache;
         _factory = factory;
@@ -76,8 +80,7 @@
 
                 try
                 {
-                    new AjaxResponseGenerator(page, (RenderCommand) result, _factory, _renderer).sendClientResponse(
-                            _response);
+                    sendClientResponse(page, (RenderCommand) result);
                 }
                 catch (IOException ex)
                 {
@@ -95,10 +98,12 @@
 
         if (exceptionHolder.hasValue()) throw exceptionHolder.get();
 
-        if (holder.hasValue()) return holder.get();
+        if (holder.hasValue()) return true;
 
         element.triggerEvent(eventType, context, handler);
 
+        if (exceptionHolder.hasValue()) throw exceptionHolder.get();
+
         if (holder.hasValue()) return true;
 
         PrintWriter pw = _response.getPrintWriter("text/javascript");
@@ -108,5 +113,36 @@
         pw.flush();
 
         return true;
+    }
+
+    public void sendClientResponse(Page page, RenderCommand rootRenderCommand) throws IOException
+    {
+        // This may be problematic as the charset of the response is not
+        // going to be set properly I think.  We'll loop back to that.
+
+        ContentType contentType = new ContentType("text/javascript");
+
+        MarkupWriter writer = _factory.newMarkupWriter();
+
+        // The partial will quite often contain multiple elements (or just a block of plain text),
+        // so those must be enclosed in a root element.
+
+        Element root = writer.element("ajax-partial");
+
+        _renderer.renderPartialPageMarkup(page, rootRenderCommand, writer);
+
+        writer.end();
+
+        String content = root.getChildText().trim();
+
+        JSONObject reply = new JSONObject();
+
+        reply.put("content", content);
+
+        PrintWriter pw = _response.getPrintWriter(contentType.toString());
+
+        pw.print(reply);
+
+        pw.flush();
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ClassResultProcessor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ClassResultProcessor.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ClassResultProcessor.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/ClassResultProcessor.java Sun Nov 25 21:36:17 2007
@@ -26,8 +26,6 @@
 /**
  * Used when a component event handler returns a class value. The value is interpreted as the page
  * class. A link to the page will be sent.
- *
- * @see LinkActionResponseGenerator
  */
 public class ClassResultProcessor implements ComponentEventResultProcessor<Class>
 {

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRenderer.java Sun Nov 25 21:36:17 2007
@@ -1,46 +1,34 @@
-// Copyright 2006 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.
-
+// Copyright 2006 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.MarkupWriter;
 import org.apache.tapestry.internal.structure.Page;
-import org.apache.tapestry.runtime.RenderCommand;
 
 /**
- * Service used to render page markup using a MarkupWriter.  This is usually used when rendering a complete
+ * Service used to render page markup using a MarkupWriter.  This is  used when rendering a complete
  * page as part of a {@linkplain org.apache.tapestry.internal.services.PageRenderRequestHandlerImpl page render request},
- * but may also be used to render portions of a page as part of an {@linkplain org.apache.tapestry.internal.services.AjaxResponseGenerator Ajax request}.
  */
 public interface PageMarkupRenderer
 {
     /**
      * Initializes the rendering using the
-     * {@link org.apache.tapestry.services.PageRenderInitializer} change of command.
+     * {@link org.apache.tapestry.services.PageRenderInitializer} chain of command.
      *
      * @param page   page to render
      * @param writer receives the markup
      */
     void renderPageMarkup(Page page, MarkupWriter writer);
-
-    /**
-     * Used to render a partial response as part of an Ajax action request.
-     *
-     * @param page              page used to perform the render
-     * @param rootRenderCommand initial object to render
-     * @param writer            writer used to perform the render
-     */
-    void renderPartialPageMarkup(Page page, RenderCommand rootRenderCommand, MarkupWriter writer);
-
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageMarkupRendererImpl.java Sun Nov 25 21:36:17 2007
@@ -16,38 +16,54 @@
 
 import org.apache.tapestry.MarkupWriter;
 import org.apache.tapestry.internal.structure.Page;
-import org.apache.tapestry.runtime.RenderCommand;
+import org.apache.tapestry.services.Environment;
+import org.apache.tapestry.services.MarkupRenderer;
 import org.apache.tapestry.services.PageRenderInitializer;
 
 public class PageMarkupRendererImpl implements PageMarkupRenderer
 {
-    private final PageRenderInitializer _pageRenderInitializer;
+    private final Environment _environment;
 
-    public PageMarkupRendererImpl(PageRenderInitializer pageRenderInitializer)
+    private final PageRenderQueue _pageRenderQueue;
+
+    private final MarkupRenderer _markupRendererPipeline;
+
+    public PageMarkupRendererImpl(PageRenderInitializer pageRenderInitializer, PageRenderQueue pageRenderQueue,
+                                  Environment environment)
     {
-        _pageRenderInitializer = pageRenderInitializer;
+        // We have to go through some awkward tricks here:
+        // - MarkupRenderer and MarkupRendererFilter are PUBLIC
+        // - Page, PageMarkupRenderer, PageRenderQueue are PRIVATE
+        // - This service is the bridge between public and private
+
+
+        _pageRenderQueue = pageRenderQueue;
+        _environment = environment;
+
+        MarkupRenderer renderer = new MarkupRenderer()
+        {
+            public void renderMarkup(MarkupWriter writer)
+            {
+                _pageRenderQueue.render(writer);
+            }
+        };
+
+        _markupRendererPipeline = pageRenderInitializer.addFilters(renderer);
     }
 
     public void renderPageMarkup(Page page, MarkupWriter writer)
     {
-        _pageRenderInitializer.setup(writer);
+        _environment.clear();
 
-        renderPartialPageMarkup(page, page.getRootElement(), writer);
+        // This is why the PRQ is scope perthread; we tell it what to render here ...
 
-        _pageRenderInitializer.cleanup(writer);
+        _pageRenderQueue.initializeForCompletePage(page);
 
-        if (writer.getDocument().getRootElement() == null)
-            throw new RuntimeException(ServicesMessages.noMarkupFromPageRender(page));
-    }
+        // ... then our fixed pipeline is able to (eventually) call into it.
 
-    public void renderPartialPageMarkup(Page page, RenderCommand rootRenderCommand, MarkupWriter writer)
-    {
-        RenderQueueImpl queue = new RenderQueueImpl(page.getLogger());
-
-        queue.push(rootRenderCommand);
-
-        // Run the queue until empty.
+        _markupRendererPipeline.renderMarkup(writer);
 
-        queue.run(writer);
+        if (writer.getDocument().getRootElement() == null)
+            throw new RuntimeException(ServicesMessages.noMarkupFromPageRender(page));
     }
 }

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderInitializerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderInitializerImpl.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderInitializerImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderInitializerImpl.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,48 @@
+// 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.ioc.services.PipelineBuilder;
+import org.apache.tapestry.services.MarkupRenderer;
+import org.apache.tapestry.services.MarkupRendererFilter;
+import org.apache.tapestry.services.PageRenderInitializer;
+import org.slf4j.Logger;
+
+import java.util.List;
+
+public class PageRenderInitializerImpl implements PageRenderInitializer
+{
+    private final Logger _logger;
+
+    private final PipelineBuilder _builder;
+
+    private final List<MarkupRendererFilter> _configuration;
+
+    public PageRenderInitializerImpl(Logger logger, PipelineBuilder builder, List<MarkupRendererFilter> configuration)
+    {
+        _builder = builder;
+        _configuration = configuration;
+        _logger = logger;
+    }
+
+    // In the scheme of things, this method is only called once. We've jumped through
+    // some very special hoops to allow extensions to the rendering pipeline without
+    // revealing any private classes, and this service is an important piece of that.
+
+    public MarkupRenderer addFilters(MarkupRenderer renderer)
+    {
+        return _builder.build(_logger, MarkupRenderer.class, MarkupRendererFilter.class, _configuration, renderer);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueue.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueue.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueue.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueue.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,46 @@
+// 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.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.RenderCommand;
+
+
+/**
+ * A wrapper around {@link org.apache.tapestry.runtime.RenderQueue}, but referencable as
+ * a (per-thread) service.     This service is scoped so that we can tell it what to render
+ * in one method, then have it do the render in another. Part of an elaborate
+ * scheme to keep certain interfaces public and other closely related ones private.
+ */
+public interface PageRenderQueue
+{
+    /**
+     * Initializes the queue for rendering of a complete page.
+     */
+    void initializeForCompletePage(Page page);
+
+    /**
+     * Initializes the queue for rendering of a portion of a page.
+     */
+    void initializeForPartialPageRender(Page page, RenderCommand rootCommand);
+
+    /**
+     * Render to the write, as setup by the initialize method.
+     *
+     * @param writer to write markup to
+     */
+    void render(MarkupWriter writer);
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueueImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueueImpl.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueueImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PageRenderQueueImpl.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,52 @@
+// 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.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+import static org.apache.tapestry.ioc.IOCConstants.PERTHREAD_SCOPE;
+import org.apache.tapestry.ioc.annotations.Scope;
+import org.apache.tapestry.runtime.RenderCommand;
+
+@Scope(PERTHREAD_SCOPE)
+public class PageRenderQueueImpl implements PageRenderQueue
+{
+    private Page _page;
+
+    private RenderCommand _rootCommand;
+
+    public void initializeForCompletePage(Page page)
+    {
+        _page = page;
+        _rootCommand = page.getRootElement();
+    }
+
+    public void initializeForPartialPageRender(Page page, RenderCommand rootCommand)
+    {
+        _page = page;
+        _rootCommand = rootCommand;
+    }
+
+    public void render(MarkupWriter writer)
+    {
+        RenderQueueImpl queue = new RenderQueueImpl(_page.getLogger());
+
+        queue.push(_rootCommand);
+
+        // Run the queue until empty.
+
+        queue.run(writer);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRenderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRenderer.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRenderer.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRenderer.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,35 @@
+// 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.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.RenderCommand;
+
+/**
+ * Used to render portions of a page as part of an
+ * {@linkplain AjaxComponentActionRequestHandler Ajax request}.
+ */
+public interface PartialMarkupRenderer
+{
+    /**
+     * Used to render a partial response as part of an Ajax action request.
+     *
+     * @param page              page used to perform the render
+     * @param rootRenderCommand initial object to render
+     * @param writer            writer used to perform the render
+     */
+    void renderPartialPageMarkup(Page page, RenderCommand rootRenderCommand, MarkupWriter writer);
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRendererImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRendererImpl.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRendererImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/internal/services/PartialMarkupRendererImpl.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,44 @@
+// 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.MarkupWriter;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.RenderCommand;
+import org.apache.tapestry.services.Environment;
+
+public class PartialMarkupRendererImpl implements PartialMarkupRenderer
+{
+    private final Environment _environment;
+
+    private final PageRenderQueue _pageRenderQueue;
+
+    public PartialMarkupRendererImpl(Environment environment, PageRenderQueue pageRenderQueue)
+    {
+        _environment = environment;
+        _pageRenderQueue = pageRenderQueue;
+    }
+
+    public void renderPartialPageMarkup(Page page, RenderCommand rootRenderCommand, MarkupWriter writer)
+    {
+        _environment.clear();
+
+        _pageRenderQueue.initializeForPartialPageRender(page, rootRenderCommand);
+
+        // No pipeline for partial rendering, yet.
+
+        _pageRenderQueue.render(writer);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRenderer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRenderer.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRenderer.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRenderer.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,31 @@
+// 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.services;
+
+import org.apache.tapestry.MarkupWriter;
+
+/**
+ * An object which will perform rendering of a page (or portion of a page).  This interface
+ * exists to be filtered via {@link org.apache.tapestry.services.MarkupRendererFilter}.
+ */
+public interface MarkupRenderer
+{
+    /**
+     * Invoked to render some markup.
+     *
+     * @param writer to which markup should be written
+     */
+    void renderMarkup(MarkupWriter writer);
+}

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRendererFilter.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRendererFilter.java?rev=598137&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRendererFilter.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/MarkupRendererFilter.java Sun Nov 25 21:36:17 2007
@@ -0,0 +1,34 @@
+// 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.services;
+
+import org.apache.tapestry.MarkupWriter;
+
+/**
+ * Filter interface for {@link org.apache.tapestry.services.MarkupRenderer}, which allows
+ * for code to execute before and/or after the main rendering process.  Typically, this is to
+ * allow for the placement of {@linkplain org.apache.tapestry.services.Environment environmental services}.
+ */
+public interface MarkupRendererFilter
+{
+    /**
+     * Implementations should perform work before or after passing the writer
+     * to the renderer.
+     *
+     * @param writer   to which markup sholuld be written
+     * @param renderer delegate to which the writer should be passed.
+     */
+    void renderMarkup(MarkupWriter writer, MarkupRenderer renderer);
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/PageRenderInitializer.java Sun Nov 25 21:36:17 2007
@@ -14,27 +14,18 @@
 
 package org.apache.tapestry.services;
 
-import org.apache.tapestry.MarkupWriter;
-
 /**
- * Responsible for setup and cleanup of the rendering of a page. The implementation of this is based
- * on an ordered list of {@link PageRenderCommand}s.
+ * Service to which an ordered collection of {@link org.apache.tapestry.services.MarkupRendererFilter}s is
+ * provided, which can then merge the filters with an eactual {@link org.apache.tapestry.services.MarkupRenderer}.
  */
 public interface PageRenderInitializer
 {
     /**
-     * Perform any initial setup, by invoking {@link PageRenderCommand#setup(Environment)}.
-     * Execution occurs in normal order.
+     * Creates a new MarkupRenderer by wrapping the provided renderer with
+     * the {@link org.apache.tapestry.services.MarkupRendererFilter}s configured for the service.
      *
-     * @param writer the markup writer that will be used to generate all output markup
+     * @param renderer the renderer at the end of the filter chain
+     * @return a new renderer that encapsulates the filter chain
      */
-    void setup(MarkupWriter writer);
-
-    /**
-     * Peform any post-render cleanup, by invoking {@link PageRenderCommand#cleanup(Environment)}.
-     * Execution order is reversed.
-     *
-     * @param writer the markup writer used to generate all output markup in the document
-     */
-    void cleanup(MarkupWriter writer);
+    MarkupRenderer addFilters(MarkupRenderer renderer);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry/services/TapestryModule.java Sun Nov 25 21:36:17 2007
@@ -19,8 +19,8 @@
 import org.apache.tapestry.annotations.*;
 import org.apache.tapestry.beaneditor.Validate;
 import org.apache.tapestry.corelib.data.GridPagerPosition;
-import org.apache.tapestry.dom.Document;
 import org.apache.tapestry.grid.GridDataSource;
+import org.apache.tapestry.internal.DefaultValidationDecorator;
 import org.apache.tapestry.internal.InternalConstants;
 import org.apache.tapestry.internal.TapestryInternalUtils;
 import org.apache.tapestry.internal.beaneditor.PrimitiveFieldConstraintGenerator;
@@ -110,6 +110,9 @@
         binder.bind(RequestEncodingInitializer.class, RequestEncodingInitializerImpl.class);
         binder.bind(ComponentEventResultProcessor.class, ComponentInstanceResultProcessor.class).withId(
                 "ComponentInstanceResultProcessor");
+        binder.bind(PageRenderQueue.class, PageRenderQueueImpl.class);
+        binder.bind(PageRenderInitializer.class, PageRenderInitializerImpl.class);
+        binder.bind(PartialMarkupRenderer.class, PartialMarkupRendererImpl.class);
     }
 
     public static Alias build(Logger logger,
@@ -888,35 +891,6 @@
         return _chainBuilder.build(InjectionProvider.class, configuration);
     }
 
-    /**
-     * Controls setup and cleanup of the environment during page rendering (the generation of a
-     * markup stream response for the client web browser).
-     */
-    public PageRenderInitializer build(final List<PageRenderCommand> configuration)
-    {
-        return new PageRenderInitializer()
-        {
-            public void cleanup(MarkupWriter writer)
-            {
-                Iterator<PageRenderCommand> i = InternalUtils.reverseIterator(configuration);
-
-                while (i.hasNext()) i.next().cleanup(_environment);
-
-                _environment.clear();
-            }
-
-            public void setup(MarkupWriter writer)
-            {
-                _environment.clear();
-
-                _environment.push(MarkupWriter.class, writer);
-                _environment.push(Document.class, writer.getDocument());
-
-                for (PageRenderCommand command : configuration)
-                    command.setup(_environment);
-            }
-        };
-    }
 
     /**
      * Initializes the application.
@@ -1256,7 +1230,16 @@
         configuration.add(ClassTransformation.class, preformatted);
     }
 
-    public void contributePageRenderInitializer(OrderedConfiguration<PageRenderCommand> configuration,
+    /**
+     * Adds basic render initializers:
+     * <dl>
+     * <dt>PageRenderSupport</dt>  <dd>Provides {@link PageRenderSupport}</dd>
+     * <dt>Heartbeat</dt> <dd>Provides {@link org.apache.tapestry.services.Heartbeat}</dd>
+     * <dt>DefaultValidationDecorator</dt>
+     * <dd>Provides {@link org.apache.tapestry.ValidationDecorator} (as {@link org.apache.tapestry.internal.DefaultValidationDecorator})</dd>
+     * </dl>
+     */
+    public void contributePageRenderInitializer(OrderedConfiguration<MarkupRendererFilter> configuration,
 
                                                 ThreadLocale threadLocale,
 
@@ -1264,33 +1247,20 @@
                                                 final Asset stylesheetAsset,
 
                                                 @Path("org/apache/tapestry/field-error-marker.png")
-                                                Asset fieldErrorIcon,
+                                                final Asset fieldErrorIcon,
 
-                                                ValidationMessagesSource validationMessagesSource,
+                                                final ValidationMessagesSource validationMessagesSource,
 
                                                 final SymbolSource symbolSource,
 
                                                 final AssetSource assetSource)
     {
-        configuration.add("PageRenderSupport", new PageRenderCommand()
+        MarkupRendererFilter pageRenderSupport = new MarkupRendererFilter()
         {
-            public void cleanup(Environment environment)
-            {
-                environment.pop(PageRenderSupport.class);
-
-                Document document = environment.peek(Document.class);
-
-                DocumentHeadBuilder builder = environment.pop(DocumentHeadBuilder.class);
-
-                builder.updateDocument(document);
-            }
-
-            public void setup(Environment environment)
+            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
             {
                 DocumentHeadBuilder builder = new DocumentHeadBuilderImpl();
 
-                environment.push(DocumentHeadBuilder.class, builder);
-
                 PageRenderSupportImpl support = new PageRenderSupportImpl(builder, symbolSource, assetSource,
 
                                                                           // Core scripts added to any page that uses scripting
@@ -1298,33 +1268,62 @@
                                                                           "${tapestry.scriptaculous}/prototype.js",
                                                                           "${tapestry.scriptaculous}/scriptaculous.js",
                                                                           "${tapestry.scriptaculous}/effects.js",
+
+                                                                          // Uses functions defined by the prior three
+
                                                                           "org/apache/tapestry/tapestry.js");
 
                 support.addStylesheetLink(stylesheetAsset, null);
 
-                environment.push(PageRenderSupport.class, support);
+                _environment.push(PageRenderSupport.class, support);
+
+                renderer.renderMarkup(writer);
+
+                builder.updateDocument(writer.getDocument());
+
+                _environment.pop(PageRenderSupport.class);
             }
-        });
+        };
 
-        configuration.add("Heartbeat", new PageRenderCommand()
+        MarkupRendererFilter heartbeat = new MarkupRendererFilter()
         {
-            public void cleanup(Environment environment)
+            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
             {
-                environment.pop(Heartbeat.class).end();
+                Heartbeat heartbeat = new HeartbeatImpl();
+
+                heartbeat.begin();
+
+                _environment.push(Heartbeat.class, heartbeat);
+
+                renderer.renderMarkup(writer);
+
+                _environment.pop(Heartbeat.class);
+
+                heartbeat.end();
             }
+        };
 
-            public void setup(Environment environment)
+        MarkupRendererFilter defaultValidationDecorator = new MarkupRendererFilter()
+        {
+            public void renderMarkup(MarkupWriter writer, MarkupRenderer renderer)
             {
-                HeartbeatImpl heartbeat = new HeartbeatImpl();
+                Messages messages = validationMessagesSource.getValidationMessages(_threadLocale.getLocale());
 
-                heartbeat.begin();
+                ValidationDecorator decorator = new DefaultValidationDecorator(_environment, messages, fieldErrorIcon,
+                                                                               writer);
 
-                environment.push(Heartbeat.class, heartbeat);
+                _environment.push(ValidationDecorator.class, decorator);
+
+                renderer.renderMarkup(writer);
+
+                _environment.pop(ValidationDecorator.class);
             }
-        });
+        };
+
 
-        configuration.add("DefaultValidationDelegate",
-                          new DefaultValidationDelegateCommand(threadLocale, validationMessagesSource, fieldErrorIcon));
+        configuration.add("PageRenderSupport", pageRenderSupport);
+        configuration.add("Heartbeat", heartbeat);
+        configuration.add("DefaultValidationDecorator", defaultValidationDecorator);
     }
 
     /**

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java?rev=598137&r1=598136&r2=598137&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry/internal/DefaultValidationDecoratorTest.java Sun Nov 25 21:36:17 2007
@@ -34,7 +34,7 @@
 
         replay();
 
-        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null, null);
 
         decorator.insideLabel(null, null);
 
@@ -56,7 +56,7 @@
 
         Element e = writer.element("label", "accesskey", "f");
 
-        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null, null);
 
         decorator.insideLabel(field, e);
 
@@ -80,7 +80,7 @@
 
         Element e = writer.element("label", "accesskey", "f", "class", "foo");
 
-        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null, null);
 
         decorator.insideLabel(field, e);
 
@@ -99,30 +99,17 @@
 
         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");
+        writer.element("input", "type", "text", "name", "ex", "class", "foo", "value", "freddy", "size", "30");
 
-        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null, writer);
 
         decorator.insideField(field);
 
-        assertEquals(
-                writer.toString(),
-                "<input class=\"foo t-error\" name=\"ex\" size=\"30\" type=\"text\" value=\"freddy\"/>");
+        assertEquals(writer.toString(),
+                     "<input class=\"foo t-error\" name=\"ex\" size=\"30\" type=\"text\" value=\"freddy\"/>");
 
         verify();
     }
@@ -139,7 +126,7 @@
 
         replay();
 
-        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null, null);
 
         decorator.insideField(field);
 
@@ -158,7 +145,7 @@
 
         replay();
 
-        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null);
+        ValidationDecorator decorator = new DefaultValidationDecorator(env, null, null, null);
 
         decorator.insideLabel(field, null);