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/01/11 05:45:05 UTC

svn commit: r495111 - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/internal/ main/java/org/apache/tapestry/internal/services/ main/java/org/apache/tapestry/internal/structure/ main/java/org/apache/tapestry/runtime/ main...

Author: hlship
Date: Wed Jan 10 20:45:04 2007
New Revision: 495111

URL: http://svn.apache.org/viewvc?view=rev&rev=495111
Log:
Add support for render phase methods returning component instances (which are then rendered).

Added:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RenderCommandWorker.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/RenderComponentDemo.html
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/NeverRender.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Render.java
    tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/RenderComponentDemo.java
Modified:
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EventImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/Event.java
    tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/services/TapestryModule.java
    tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt
    tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
    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/structure/ComponentPageElementImplTest.java

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/InternalComponentResourcesCommon.java Wed Jan 10 20:45:04 2007
@@ -12,61 +12,65 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.apache.tapestry.internal;
-
+package org.apache.tapestry.internal;
+
 import org.apache.tapestry.Binding;
-import org.apache.tapestry.internal.structure.ComponentPageElement;
-import org.apache.tapestry.internal.structure.Page;
-import org.apache.tapestry.runtime.Component;
-import org.apache.tapestry.services.PersistentFieldManager;
-
-/**
- * Operations shared by {@link InternalComponentResources} and {@link ComponentPageElement}.
- * Typically, these means methods of InternalComponentResources that are delegated to the component
- * page element.
- */
-public interface InternalComponentResourcesCommon
-{
-    /**
-     * Get the current persisted value of the field.
-     * 
-     * @param fieldName
-     *            the name of the field to access
-     * @return the value stored for the field, or null if no value is currently stored
-     */
-    Object getFieldChange(String fieldName);
-
-    /**
-     * Posts a change to a persistent field. If the component is still loading, then this change is
-     * ignored. Otherwise, it is propogated, via the
-     * {@link Page#persistFieldChange(org.apache.tapestry.internal.structure.ComponentPageElement, String, Object) page}
-     * to the {@link PersistentFieldManager}.
-     */
-    void persistFieldChange(String fieldName, Object newValue);
-
-    /** Checks to see if there is a value stored for the indicated field. */
-    boolean hasFieldChange(String fieldName);
-
-    /**
-     * Returns true if the component has finished loading. Initially, this value will be false.
-     * 
-     * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()
-     */
-    boolean isLoaded();
-
-    /**
-     * Used during construction of the page to identify the binding for a particular parameter.
-     * <p>
-     * TODO: Would prefer to move this to a sub-interface, say "MutableInternalComponentResources".
-     */
-    void addParameter(String parameterName, Binding binding);
-
-    /**
-     * Returns the mixin instance for the fully qualfied mixin class name.
-     * 
-     * @param mixinClassName
-     *            fully qualified class name
-     * @return IllegalArgumentException if no such mixin is associated with the core component
-     */
-    Component getMixinByClassName(String mixinClassName);
-}
+import org.apache.tapestry.internal.structure.ComponentPageElement;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.runtime.RenderQueue;
+import org.apache.tapestry.services.PersistentFieldManager;
+
+/**
+ * Operations shared by {@link InternalComponentResources} and {@link ComponentPageElement}.
+ * Typically, these means methods of InternalComponentResources that are delegated to the component
+ * page element.
+ */
+public interface InternalComponentResourcesCommon
+{
+    /**
+     * Get the current persisted value of the field.
+     * 
+     * @param fieldName
+     *            the name of the field to access
+     * @return the value stored for the field, or null if no value is currently stored
+     */
+    Object getFieldChange(String fieldName);
+
+    /**
+     * Posts a change to a persistent field. If the component is still loading, then this change is
+     * ignored. Otherwise, it is propogated, via the
+     * {@link Page#persistFieldChange(org.apache.tapestry.internal.structure.ComponentPageElement, String, Object) page}
+     * to the {@link PersistentFieldManager}.
+     */
+    void persistFieldChange(String fieldName, Object newValue);
+
+    /** Checks to see if there is a value stored for the indicated field. */
+    boolean hasFieldChange(String fieldName);
+
+    /**
+     * Returns true if the component has finished loading. Initially, this value will be false.
+     * 
+     * @see org.apache.tapestry.runtime.PageLifecycleListener#containingPageDidLoad()
+     */
+    boolean isLoaded();
+
+    /**
+     * Used during construction of the page to identify the binding for a particular parameter.
+     * <p>
+     * TODO: Would prefer to move this to a sub-interface, say "MutableInternalComponentResources".
+     */
+    void addParameter(String parameterName, Binding binding);
+
+    /**
+     * Returns the mixin instance for the fully qualfied mixin class name.
+     * 
+     * @param mixinClassName
+     *            fully qualified class name
+     * @return IllegalArgumentException if no such mixin is associated with the core component
+     */
+    Component getMixinByClassName(String mixinClassName);
+
+    /** Invoked to make the receiver queue itself to be rendered. */
+    void queueRender(RenderQueue queue);
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EventImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EventImpl.java?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EventImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/EventImpl.java Wed Jan 10 20:45:04 2007
@@ -1,3 +1,17 @@
+// 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 static org.apache.tapestry.ioc.internal.util.Defense.notNull;

Added: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RenderCommandWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RenderCommandWorker.java?view=auto&rev=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RenderCommandWorker.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/RenderCommandWorker.java Wed Jan 10 20:45:04 2007
@@ -0,0 +1,51 @@
+// 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 java.lang.reflect.Modifier;
+
+import org.apache.tapestry.MarkupWriter;
+import org.apache.tapestry.internal.InternalComponentResourcesCommon;
+import org.apache.tapestry.model.MutableComponentModel;
+import org.apache.tapestry.runtime.RenderCommand;
+import org.apache.tapestry.runtime.RenderQueue;
+import org.apache.tapestry.services.ClassTransformation;
+import org.apache.tapestry.services.ComponentClassTransformWorker;
+import org.apache.tapestry.services.MethodSignature;
+
+/**
+ * Ensures that all components implement {@link RenderCommand} by delegating to
+ * {@link InternalComponentResourcesCommon#queueRender(org.apache.tapestry.runtime.RenderQueue)}.
+ */
+public class RenderCommandWorker implements ComponentClassTransformWorker
+{
+    private final MethodSignature RENDER_SIGNATURE = new MethodSignature(Modifier.PUBLIC, "void",
+            "render", new String[]
+            { MarkupWriter.class.getName(), RenderQueue.class.getName() }, null);
+
+    public void transform(ClassTransformation transformation, MutableComponentModel model)
+    {
+        // Subclasses don't need to bother, they'll inherit from super-classes.
+
+        if (model.getParentModel() != null)
+            return;
+
+        transformation.addImplementedInterface(RenderCommand.class);
+
+        String body = String.format("%s.queueRender($2);", transformation.getResourcesFieldName());
+
+        transformation.addMethod(RENDER_SIGNATURE, body);
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/ComponentPageElementImpl.java Wed Jan 10 20:45:04 2007
@@ -115,6 +115,8 @@
     {
         private boolean _result;
 
+        private List<RenderCommand> _commands;
+
         public RenderPhaseEventHandler(boolean defaultResult)
         {
             _result = defaultResult;
@@ -130,15 +132,38 @@
             if (result instanceof Boolean)
             {
                 _result = (Boolean) result;
+                return true; // abort other handler methods
             }
-            else
+
+            if (result instanceof RenderCommand)
             {
-                throw new TapestryException(StructureMessages.wrongEventResultType(
-                        methodDescription,
-                        Boolean.class), component, null);
+                RenderCommand command = (RenderCommand) result;
+
+                add(command);
+
+                return false; // do not abort!
             }
 
-            return true; // Abort the event
+            throw new TapestryException(StructureMessages.wrongEventResultType(
+                    methodDescription,
+                    Boolean.class), component, null);
+        }
+
+        private void add(RenderCommand command)
+        {
+            if (_commands == null)
+                _commands = newList();
+
+            _commands.add(command);
+        }
+
+        public void queueCommands(RenderQueue queue)
+        {
+            if (_commands == null)
+                return;
+
+            for (RenderCommand command : _commands)
+                queue.push(command);
         }
     };
 
@@ -161,6 +186,8 @@
 
             if (handler.getResult())
                 queue.push(_beginRender);
+
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -189,6 +216,8 @@
 
             if (handler.getResult())
                 queue.push(_beforeRenderBody);
+
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -217,6 +246,8 @@
 
             if (handler.getResult())
                 queue.push(_beforeRenderTemplate);
+
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -247,6 +278,8 @@
 
             if (handler.getResult())
                 pushElements(queue, _body);
+
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -277,6 +310,8 @@
 
             if (handler.getResult())
                 pushElements(queue, _template);
+
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -313,6 +348,7 @@
                 queue.push(_beforeRenderTemplate);
             }
 
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -362,6 +398,7 @@
                 _page.decrementDirtyCount();
             }
 
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -394,8 +431,6 @@
 
     private boolean _loaded;
 
-    private final Log _log;
-
     /** Map from mixin name to resources for the mixin. Created when first mixin is added. */
     private Map<String, InternalComponentResources> _mixinsByShortName;
 
@@ -428,6 +463,8 @@
 
             if (handler.getResult())
                 queue.push(_beginRender);
+
+            handler.queueCommands(queue);
         }
 
         @Override
@@ -437,6 +474,9 @@
         }
     };
 
+    // We know that, at the very least, there will be an element to force the component to render its body,
+    // so there's no reason to wait to initialize the list.
+    
     private final List<PageElement> _template = newList();
 
     private final TypeCoercer _typeCoercer;
@@ -471,15 +511,12 @@
     {
         super(location);
 
-        ComponentModel model = instantiator.getModel();
-
         _page = page;
         _container = container;
         _id = id;
         _elementName = elementName;
         _typeCoercer = typeCoercer;
         _messagesSource = messagesSource;
-        _log = model.getLog();
 
         _coreResources = new InternalComponentResourcesImpl(this, instantiator, _typeCoercer,
                 _messagesSource);
@@ -900,6 +937,9 @@
     /** Pushes the SetupRender phase state onto the queue. */
     public final void render(MarkupWriter writer, RenderQueue queue)
     {
+        // TODO: An error if the _render flag is already set (recursive rendering not
+        // allowed or advisable).
+        
         // Once we start rendering, the page is considered dirty, until we cleanup post render.
 
         _page.incrementDirtyCount();
@@ -963,6 +1003,11 @@
     public String getElementName()
     {
         return _elementName;
+    }
+
+    public void queueRender(RenderQueue queue)
+    {
+        queue.push(this);
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/structure/InternalComponentResourcesImpl.java Wed Jan 10 20:45:04 2007
@@ -33,6 +33,7 @@
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.model.ComponentModel;
 import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.runtime.RenderQueue;
 import org.apache.tapestry.services.ComponentMessagesSource;
 
 /**
@@ -285,6 +286,11 @@
     public String getElementName()
     {
         return _element.getElementName();
+    }
+
+    public void queueRender(RenderQueue queue)
+    {
+        _element.queueRender(queue);
     }
 
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/Event.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/Event.java?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/Event.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/runtime/Event.java Wed Jan 10 20:45:04 2007
@@ -1,3 +1,17 @@
+// 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.runtime;
 
 import org.apache.tapestry.ComponentEventHandler;

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=495111&r1=495110&r2=495111
==============================================================================
--- 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 Wed Jan 10 20:45:04 2007
@@ -98,6 +98,7 @@
 import org.apache.tapestry.internal.services.ParameterWorker;
 import org.apache.tapestry.internal.services.PersistWorker;
 import org.apache.tapestry.internal.services.PersistentFieldManagerImpl;
+import org.apache.tapestry.internal.services.RenderCommandWorker;
 import org.apache.tapestry.internal.services.RequestGlobalsImpl;
 import org.apache.tapestry.internal.services.RequestImpl;
 import org.apache.tapestry.internal.services.RequestPageCache;
@@ -142,6 +143,7 @@
 import org.apache.tapestry.ioc.services.TypeCoercer;
 import org.apache.tapestry.ioc.util.StrategyRegistry;
 import org.apache.tapestry.runtime.Component;
+import org.apache.tapestry.runtime.RenderCommand;
 import org.apache.tapestry.translator.IntegerTranslator;
 import org.apache.tapestry.translator.StringTranslator;
 import org.apache.tapestry.validator.Required;
@@ -630,6 +632,7 @@
      * <li>SupportsInformalParameters -- checks for the annotation</li>
      * <li>UnclaimedField -- identifies unclaimed fields and resets them to null/0/false at the end
      * of the request</li>
+     * <li>RenderCommand -- ensures all components also implement {@link RenderCommand}</li>
      * <li>SetupRender, BeginRender, etc. -- correspond to component render phases and annotations</li>
      * </ul>
      */
@@ -662,6 +665,7 @@
         configuration.add("SupportsInformalParameters", new SupportsInformalParametersWorker());
         configuration.add("InjectPage", new InjectPageWorker(requestPageCache));
         configuration.add("InjectComponent", new InjectComponentWorker());
+        configuration.add("RenderCommand", new RenderCommandWorker());
 
         // Default values for parameters are often some form of injection, so make sure
         // that Parameter fields are processed after injections.

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/rendering.apt Wed Jan 10 20:45:04 2007
@@ -263,6 +263,23 @@
   to some eyes, more descriptive).
   
   You can, of course, mix and match, using specifically named render phase methods in some cases, and annotated render phase methods in other cases. 
+  
+Rendering Components
+
+  Instead of returning true or false, a render phase method may return a component. The component may have been injected via the
+  {{{.../apidocs/org/apache/tapestry/annotations/Component.html}Component}} annotation, or may have been passed to the 
+  as a parameter.
+  
+  In any case, returning a component will queue that component to be rendered <<before>> the active component continues rendering.
+  
+  The component to render may even be from a completely different page of the application.
+  
+  Recursive rendering of components is not allowed.
+  
+  This technique allows the rendering of Tapestry pages to be <highly> dynamic.  
+  
+  Returning a component instance does <<not>> short circuit method invocation, the way returning a boolean would.  It is possible
+  that multiple  methods may return components (this is not advised -- insanity may ensue).  
 
 Method Conflicts and Ordering
 

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/RenderComponentDemo.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/RenderComponentDemo.html?view=auto&rev=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/RenderComponentDemo.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/WEB-INF/RenderComponentDemo.html Wed Jan 10 20:45:04 2007
@@ -0,0 +1,28 @@
+<html t:type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    
+  <h1>Render Component Demo</h1>
+  
+    <p>
+        This page demonstrates how a component may return a component instance from one of its render phase methods to allow that object to render.
+    </p>
+
+    <t:comp type="NeverRender">
+        <span t:id="optional">
+            Optional Text
+        </span>
+    </t:comp>
+    
+    <form t:type="Form">
+        <input t:type="Checkbox" t:id="enabled" onchange="'this.form.submit();'"/> <label for="enabled">Enable optional text</label>
+    </form>
+    
+    <t:comp type="If" test="enabled">
+        Should now show up:
+    </t:comp>
+    <t:comp type="If" test="disabled">
+        Should be blank:
+    </t:comp>
+    <span id="container">[<t:comp type="Render" value="thing"/>]</span>
+    
+    
+</html>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Wed Jan 10 20:45:04 2007
@@ -6,70 +6,87 @@
         <p>
             <em>This page is static.</em>
         </p>
-        <p> Tapestry 5 Integration Application 1: <ul>
-                <li>
-                    <a href="Start.html">Start Page</a>
-                </li>
-                <li>
-                    <a href="MerryChristmas.html">Count Page</a>
-                </li>
-                <li>
-                    <a href="InjectDemo.html">Inject Demo</a>
-                </li>
-                <li>
-                    <a href="Countdown.html">Countdown Page</a>
-                </li>
-                <li>
-                    <a href="ParameterConflict.html">Template Overriden by Class Page</a>
-                </li>
-                <li>
-                    <a href="EnvironmentalDemo.html">Environmental Annotation Useage</a>
-                </li>
-                <li>
-                    <a href="Expansion.html">Expansion Page</a>
-                </li>
-                <li>
-                    <a href="MissingPage.html">Missing Page</a> -- Used to test exception reporting </li>
-                <li>
-                    <a href="BadTemplate.html">BadTemplate Page</a> -- More exception reporting </li>
-                <li>
-                    <a href="ActionPage.html">Action Page</a> -- tests fixture for ActionLink
-                    component </li>
-                <li>
-                    <a href="InstanceMixin.html">InstanceMixin</a> -- Mixin added to particular
-                    component instance </li>
-                <li>
-                    <a href="RenderPhaseOrder.html">RenderPhaseOrder</a> -- Order of operations when
-                    invoking render phase methods </li>
-                <li>
-                    <a href="SimpleForm.html">SimpleForm</a> -- first pass at writing Form and
-                    TextField components </li>
-                <li>
-                    <a href="NumberSelect.html">NumberSelect</a> -- passivate/activate page context
-                    demo </li>
-                <li>
-                    <a href="Localization.html">Localization</a> -- accessing localized messages
-                    from the component catalog </li>
-                <li>
-                    <a href="AssetDemo.html">AssetDemo</a> -- declaring an using Assets </li>
-                <li>
-                    <a href="ExpansionSubclass.html">ExpansionSubclass</a> -- components can inherit
-                    templates from base classes </li>
-                <li>
-                    <a href="InjectComponentMismatch.html">InjectComponentMismatch</a> -- check
-                    error reporting when @InjectComponent doesn't match the actual field type </li>
-                <li>
-                    <a href="ParameterDefault.html">ParameterDefault</a> -- defaulter methods for
-                    component parameters </li>
-                <li>
-                    <a href="ValidForm.html">ValidForm</a> -- server-side input validation</li>
-            <li>
-                <a href="AnyDemo.html">AnyDemo</a>  -- test out the Any component
-            </li>
-            <li>
-                <a href="PasswordFieldDemo.html">PasswordFieldDemo</a> -- test for the PasswordField component
-            </li>
-            </ul>
-        </p>
+        <p> Tapestry 5 Integration Application 1: </p>
+
+        <table>
+            <tr>
+                <td>
+                    <ul>
+                        <li>
+                            <a href="Start.html">Start Page</a>
+                        </li>
+                        <li>
+                            <a href="MerryChristmas.html">Count Page</a>
+                        </li>
+                        <li>
+                            <a href="InjectDemo.html">Inject Demo</a>
+                        </li>
+                        <li>
+                            <a href="Countdown.html">Countdown Page</a>
+                        </li>
+                        <li>
+                            <a href="ParameterConflict.html">Template Overriden by Class Page</a>
+                        </li>
+                        <li>
+                            <a href="EnvironmentalDemo.html">Environmental Annotation Useage</a>
+                        </li>
+                        <li>
+                            <a href="Expansion.html">Expansion Page</a>
+                        </li>
+                        <li>
+                            <a href="MissingPage.html">Missing Page</a> -- Used to test exception
+                            reporting </li>
+                        <li>
+                            <a href="BadTemplate.html">BadTemplate Page</a> -- More exception
+                            reporting </li>
+                        <li>
+                            <a href="ActionPage.html">Action Page</a> -- tests fixture for
+                            ActionLink component </li>
+                        <li>
+                            <a href="InstanceMixin.html">InstanceMixin</a> -- Mixin added to
+                            particular component instance </li>
+                        <li>
+                            <a href="RenderPhaseOrder.html">RenderPhaseOrder</a> -- Order of
+                            operations when invoking render phase methods </li>
+                    </ul>
+                </td>
+                <td>
+                    <ul>
+                        <li><a href="SimpleForm.html">SimpleForm</a> -- first pass at writing Form
+                            and TextField components </li>
+                        <li>
+                            <a href="NumberSelect.html">NumberSelect</a> -- passivate/activate page
+                            context demo </li>
+                        <li>
+                            <a href="Localization.html">Localization</a> -- accessing localized
+                            messages from the component catalog </li>
+                        <li>
+                            <a href="AssetDemo.html">AssetDemo</a> -- declaring an using Assets </li>
+                        <li>
+                            <a href="ExpansionSubclass.html">ExpansionSubclass</a> -- components can
+                            inherit templates from base classes </li>
+                        <li>
+                            <a href="InjectComponentMismatch.html">InjectComponentMismatch</a> --
+                            check error reporting when @InjectComponent doesn't match the actual
+                            field type </li>
+                        <li>
+                            <a href="ParameterDefault.html">ParameterDefault</a> -- defaulter
+                            methods for component parameters </li>
+                        <li>
+                            <a href="ValidForm.html">ValidForm</a> -- server-side input validation</li>
+                        <li>
+                            <a href="AnyDemo.html">AnyDemo</a> -- test out the Any component </li>
+                        <li>
+                            <a href="PasswordFieldDemo.html">PasswordFieldDemo</a> -- test for the
+                            PasswordField component </li>
+                        <li>
+                            <a href="RenderComponentDemo.html">RenderComponentDemo</a> -- components that "nominate" other components to render
+                        </li>
+                    </ul>
+                </td>
+            </tr>
+        </table>
+
+
     </body>
 </html>

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=495111&r1=495110&r2=495111
==============================================================================
--- 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 Wed Jan 10 20:45:04 2007
@@ -477,6 +477,23 @@
         assertTextPresent("[Show me the money!]");
     }
 
+    @Test
+    public void render_phase_method_returns_a_component() throws Exception
+    {
+        _selenium.open(BASE_URL);
+        clickAndWait("link=RenderComponentDemo");
+
+        assertText("//span[@id='container']", "[]");
+
+        clickAndWait("enabled");
+
+        // After clicking the link (which submits the form), the page re-renders and shows us
+        // the optional component from inside the NeverRender, resurrected to render on the page
+        // after all.
+
+        assertText("//span[@id='optional']", "Optional Text");
+    }
+
     private byte[] readContent(URL url) throws Exception
     {
         InputStream is = new BufferedInputStream(url.openStream());

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/NeverRender.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/NeverRender.java?view=auto&rev=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/NeverRender.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/NeverRender.java Wed Jan 10 20:45:04 2007
@@ -0,0 +1,32 @@
+// 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.integration.app1.components;
+
+import org.apache.tapestry.annotations.ComponentClass;
+
+/**
+ * A component that doesn't render any tag, or its body. It is used as a container of other
+ * components. This will eventually be replaced with something akin to the Block component from
+ * Tapestry 4.
+ */
+@ComponentClass
+public class NeverRender
+{
+    boolean beforeRenderBody()
+    {
+        return false;
+        
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Render.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Render.java?view=auto&rev=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Render.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/components/Render.java Wed Jan 10 20:45:04 2007
@@ -0,0 +1,36 @@
+// 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.integration.app1.components;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Parameter;
+
+@ComponentClass
+public class Render
+{
+    @Parameter(required = true)
+    private Object _value;
+
+    /**
+     * Returns the value parameter, which allows another object (presumably, a component) to render
+     * first.
+     * 
+     * @return
+     */
+    Object beginRender()
+    {
+        return _value;
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/RenderComponentDemo.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/RenderComponentDemo.java?view=auto&rev=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/RenderComponentDemo.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/RenderComponentDemo.java Wed Jan 10 20:45:04 2007
@@ -0,0 +1,50 @@
+// 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.integration.app1.pages;
+
+import org.apache.tapestry.annotations.Component;
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Persist;
+import org.apache.tapestry.corelib.components.Any;
+
+@ComponentClass
+public class RenderComponentDemo
+{
+    @Persist
+    private boolean _enabled;
+
+    @Component
+    private Any _optional;
+
+    public boolean isEnabled()
+    {
+        return _enabled;
+    }
+
+    public void setEnabled(boolean enable)
+    {
+        _enabled = enable;
+    }
+
+    public boolean isDisabled()
+    {
+        return !_enabled;
+    }
+
+    public Object getThing()
+    {
+        return _enabled ? _optional : null;
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java?view=diff&rev=495111&r1=495110&r2=495111
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java Wed Jan 10 20:45:04 2007
@@ -14,7 +14,6 @@
 
 package org.apache.tapestry.internal.structure;
 
-import org.apache.commons.logging.Log;
 import org.apache.tapestry.Binding;
 import org.apache.tapestry.ComponentResources;
 import org.apache.tapestry.internal.InternalComponentResources;
@@ -42,8 +41,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, newLog());
-
         train_getParameterModel(model, "barney", null);
 
         train_getSupportsInformalParameters(model, true);
@@ -75,8 +72,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, newLog());
-
         train_getParameterNames(model, "barney");
         train_getParameterModel(model, "barney", pmodel);
 
@@ -104,8 +99,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, newLog());
-
         train_getParameterNames(model, "barney");
         train_getParameterModel(model, "barney", pmodel);
         train_isRequired(pmodel, false);
@@ -124,7 +117,6 @@
     @Test
     public void verify_required_parameters_unbound_and_required()
     {
-        Log log = newLog();
         Page page = newPage();
         ComponentPageElement container = newComponentPageElement();
         Component component = newComponent();
@@ -135,8 +127,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, log);
-
         train_getNestedId(container, null);
         train_getName(page, "foo.pages.MyPage");
 
@@ -179,7 +169,6 @@
     @Test
     public void is_invariant()
     {
-        Log log = newLog();
         Page page = newPage();
         Component component = newComponent();
         ComponentModel model = newComponentModel();
@@ -189,8 +178,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, log);
-
         train_getParameterModel(model, "barney", pmodel);
 
         train_isInvariant(binding, true);
@@ -224,8 +211,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, newLog());
-
         train_getParameterModel(model, "barney", null);
 
         train_get(binding, boundValue);
@@ -251,7 +236,6 @@
     @Test
     public void write_binding()
     {
-        Log log = newLog();
         Page page = newPage();
         Component component = newComponent();
         ComponentModel model = newComponentModel();
@@ -264,8 +248,6 @@
 
         train_getSupportsInformalParameters(model, true);
 
-        train_getLog(model, log);
-
         expect(binding.getBindingType()).andReturn(Integer.class);
 
         train_coerce(coercer, 23, Integer.class, 23);
@@ -293,8 +275,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, newLog());
-
         replay();
 
         ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, coercer, null);
@@ -316,7 +296,6 @@
     @Test
     public void get_existing_embedded_component()
     {
-        Log log = newLog();
         Page page = newPage();
         Component component = newComponent();
         ComponentModel model = newComponentModel();
@@ -326,8 +305,6 @@
 
         Instantiator ins = newInstantiator(component, model);
 
-        train_getLog(model, log);
-
         train_getId(childElement, "child");
         train_getComponent(childElement, childComponent);
 
@@ -345,7 +322,6 @@
     @Test
     public void get_mixin_by_class_name()
     {
-        Log log = newLog();
         Page page = newPage();
         Component component = newComponent();
         ComponentModel model = newComponentModel();
@@ -359,8 +335,6 @@
 
         train_getComponentClassName(mixinModel, mixinClassName);
 
-        train_getLog(model, log);
-
         replay();
 
         ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, coercer, null);
@@ -375,7 +349,6 @@
     @Test
     public void get_mixin_by_unknown_class_name()
     {
-        Log log = newLog();
         Page page = newPage();
         Component component = newComponent();
         ComponentModel model = newComponentModel();
@@ -388,8 +361,6 @@
 
         train_getComponentClassName(mixinModel, "foo.Bar");
 
-        train_getLog(model, log);
-
         replay();
 
         ComponentPageElement cpe = new ComponentPageElementImpl(page, ins, coercer, null);
@@ -413,7 +384,6 @@
     @Test
     public void set_explicit_parameter_of_unknown_mixin()
     {
-        Log log = newLog();
         Page page = newPage();
         Component component = newComponent();
         ComponentModel model = newComponentModel();
@@ -424,8 +394,6 @@
 
         Instantiator ins = newInstantiator(component, model);
         Instantiator mixinInstantiator = newInstantiator(mixin, mixinModel);
-
-        train_getLog(model, log);
 
         train_getComponentClassName(mixinModel, "foo.Fred");