Author: hlship
Date: Fri Feb 13 18:18:49 2009
New Revision: 744203

URL: http://svn.apache.org/viewvc?rev=744203&view=rev
Log:
TAP5-95: Optimize page construction for repeated construction of the same page

Added:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssemblyAction.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ParameterBinder.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/RenderAttribute.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/RenderBodyElement.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/TokenStream.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/TokenStreamImpl.java
Removed:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLoaderImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageLoaderProcessor.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PageLoaderImplTest.java
Modified:
    
tapestry/tapestry5/trunk/tapestry-component-report/src/test/java/org/apache/tapestry/mojo/ComponentReportTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/Component.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResourcesCommon.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableEmbeddedComponentModelImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/CompositeRenderCommand.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSource.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InternalModule.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageElementFactory.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageElementFactoryImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElement.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/ComponentPageElementImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/InternalComponentResourcesImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/ComponentWorker.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/EmbeddedComponentModel.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableEmbeddedComponentModel.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/MarkupUtilsTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/pagelevel/DTDTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/TapestryInternalUtilsTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/beaneditor/BeanModelUtilsTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/bindings/PropBindingFactoryTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/pageload/CompositeRenderCommandTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ComponentInstantiatorSourceImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestPathOptimizerImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/RequestSecurityManagerImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TranslatorSourceImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/URLEncoderImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/ComponentPageElementImplTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/CodeEqTest.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/json/JSONObjectTest.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/GlobPatternMatcherTest.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TypeCoercerImplTest.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/InternalUtilsTest.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/services/ClassFabUtilsTest.java
    
tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/util/TimeIntervalTest.java

Modified: 
tapestry/tapestry5/trunk/tapestry-component-report/src/test/java/org/apache/tapestry/mojo/ComponentReportTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-component-report/src/test/java/org/apache/tapestry/mojo/ComponentReportTest.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-component-report/src/test/java/org/apache/tapestry/mojo/ComponentReportTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-component-report/src/test/java/org/apache/tapestry/mojo/ComponentReportTest.java
 Fri Feb 13 18:18:49 2009
@@ -1,4 +1,4 @@
-// Copyright 2008 The Apache Software Foundation
+// Copyright 2008, 2009 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.
@@ -14,26 +14,26 @@
 
 package org.apache.tapestry.mojo;
 
+import org.apache.maven.doxia.module.xhtml.XhtmlSink;
+import org.apache.maven.doxia.module.xhtml.decoration.render.RenderingContext;
+import org.apache.maven.model.Model;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.model.Model;
 import org.apache.maven.reporting.MavenReportException;
-import org.apache.maven.doxia.module.xhtml.decoration.render.RenderingContext;
-import org.apache.maven.doxia.module.xhtml.XhtmlSink;
-import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newList;
-import org.testng.annotations.Test;
-import org.testng.annotations.DataProvider;
-import org.testng.Assert;
+import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
 import org.codehaus.plexus.util.FileUtils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.StringWriter;
+import java.lang.reflect.Field;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.lang.reflect.Field;
 
 /**
  * Tests {...@link ComponentReport}.
@@ -42,7 +42,7 @@
 {
     @Test(dataProvider = "docData")
     public void doc_generation(final Map<String, ClassDescription> 
javadocResults, String createdFile,
-                                     String tapestryDoc, String[] 
expectedSummaryParts, String[] expectedFileParts)
+                               String tapestryDoc, String[] 
expectedSummaryParts, String[] expectedFileParts)
             throws MojoExecutionException, IOException, MavenReportException
     {
         String tempDir = System.getProperty("java.io.tmpdir");
@@ -79,10 +79,10 @@
         try
         {
             initializeMojo(report, ComponentReport.class,
-                    "rootPackage", "org.apache.tapestry5.corelib",
-                    "apidocs", "apidocs",
-                    "tapestryJavadoc", tapestryDoc,
-                    "generatedDocsDirectory", tempFolder
+                           "rootPackage", "org.apache.tapestry5.corelib",
+                           "apidocs", "apidocs",
+                           "tapestryJavadoc", tapestryDoc,
+                           "generatedDocsDirectory", tempFolder
             );
         }
         catch (NoSuchFieldException e)
@@ -144,24 +144,27 @@
         }
     }
 
-    @DataProvider(name = "docData")
-    private Object[][] testData() {
+    @DataProvider
+    private Object[][] docData()
+    {
         return new Object[][] {
                 {
-                    javadocDescriptionForForm(),
-                    "ref/org/apache/tapestry5/corelib/components/Form.xml",
-                    "http://tapestry.apache.org/tapestry5/apidocs";,
-                    new 
String[]{"org.apache.tapestry5.corelib.components.Form"},
-                    new String[]{"<title>Component Reference: 
org.apache.tapestry5.corelib.components.Form</title>",
-                    "<a 
href=\"http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/EventConstants.html#PREPARE\";>"}
+                        javadocDescriptionForForm(),
+                        "ref/org/apache/tapestry5/corelib/components/Form.xml",
+                        "http://tapestry.apache.org/tapestry5/apidocs";,
+                        new String[] { 
"org.apache.tapestry5.corelib.components.Form" },
+                        new String[] {
+                                "<title>Component Reference: 
org.apache.tapestry5.corelib.components.Form</title>",
+                                "<a 
href=\"http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry5/EventConstants.html#PREPARE\";>"
 }
                 },
                 {
-                    javadocDescriptionForForm(),
-                    "ref/org/apache/tapestry5/corelib/components/Form.xml",
-                    "../apidocs",
-                    new 
String[]{"org.apache.tapestry5.corelib.components.Form"},
-                    new String[]{"<title>Component Reference: 
org.apache.tapestry5.corelib.components.Form</title>",
-                    "<a 
href=\"../../../../../../../apidocs/org/apache/tapestry5/EventConstants.html#PREPARE\">"}
+                        javadocDescriptionForForm(),
+                        "ref/org/apache/tapestry5/corelib/components/Form.xml",
+                        "../apidocs",
+                        new String[] { 
"org.apache.tapestry5.corelib.components.Form" },
+                        new String[] {
+                                "<title>Component Reference: 
org.apache.tapestry5.corelib.components.Form</title>",
+                                "<a 
href=\"../../../../../../../apidocs/org/apache/tapestry5/EventConstants.html#PREPARE\">"
 }
                 },
 
         };
@@ -174,15 +177,15 @@
                 "org.apache.tapestry5.corelib.components.Form",
                 "java.lang.Object",
                 "When it renders, it fires a 
org.apache.tapestry5.EventConstants#PREPARE_FOR_RENDER\n" +
-                " notification, followed by a 
org.apache.tapestry5.EventConstants#PREPARE",
+                        " notification, followed by a 
org.apache.tapestry5.EventConstants#PREPARE",
                 false
         );
 
         ParameterDescription paramDesc = new ParameterDescription(
                 "validationId", "String", "", "prop", false, false, true,
                 "Prefix value used when searching for validation messages and 
constraints. " +
-                "The default is the Form component's\n" +
-                " id. This is overriden by 
org.apache.tapestry5.corelib.components.BeanEditForm."
+                        "The default is the Form component's\n" +
+                        " id. This is overriden by 
org.apache.tapestry5.corelib.components.BeanEditForm."
         );
         classDesc.getParameters().put(paramDesc.getName(), paramDesc);
 

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/Component.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/Component.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/Component.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/Component.java
 Fri Feb 13 18:18:49 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2009 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.
@@ -44,11 +44,20 @@
      * Parameter bindings for the component. Each value in the array is of the 
form "name=value". The value is a binding
      * expression, with a default binding prefix of "prop:".
      */
-    String[] parameters() default {};
+    String[] parameters() default { };
 
     /**
      * If true, then the component will inherit all informal parameters from 
its parent component. The default is
      * false.
      */
     boolean inheritInformalParameters() default false;
+
+    /**
+     * A comma-separated list of parameters of the component that should be 
published as parameters of the containing
+     * component.   Binding the parameter of the outer component will bind the 
inner component's parameter, as with the
+     * "inhert:" binding prefix.
+     *
+     * @since 5.1.0.0
+     */
+    String publishParameters() default "";
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResourcesCommon.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResourcesCommon.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResourcesCommon.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalComponentResourcesCommon.java
 Fri Feb 13 18:18:49 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2007, 2008 The Apache Software Foundation
+// Copyright 2006, 2007, 2008, 2009 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.
@@ -40,6 +40,15 @@
     void bindParameter(String parameterName, Binding binding);
 
     /**
+     * Returns the binding for the given parameter name, or null.
+     *
+     * @param parameterName name of component parameter
+     * @return binding if bound, or null
+     * @since 5.1.0.0
+     */
+    Binding getBinding(String parameterName);
+
+    /**
      * Returns the mixin instance for the fully qualfied mixin class name.
      *
      * @param mixinClassName fully qualified class name

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/InternalConstants.java
 Fri Feb 13 18:18:49 2009
@@ -110,4 +110,12 @@
      * @since 5.1.0.0
      */
     public static final String GZIP_CONTENT_ENCODING = "gzip";
+    /**
+     * Identifies the start of an expansion inside a template.
+     */
+    public static final String EXPANSION_START = "${";
+    /**
+     * Special prefix for parameters that are inherited from named parameters 
of their container.
+     */
+    public static final String INHERIT_BINDING_PREFIX = "inherit:";
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/TapestryInternalUtils.java
 Fri Feb 13 18:18:49 2009
@@ -383,13 +383,16 @@
     }
 
     /**
-     * Splits a value around commas.
+     * Splits a value around commas.  Whitespace around the commas is removed, 
as is leading and trailing whitespace.
      *
      * @since 5.1.0.0
      */
     public static String[] splitAtCommas(String value)
     {
-        return COMMA_PATTERN.split(value);
+        if (value == null)
+            return new String[0];
+
+        return COMMA_PATTERN.split(value.trim());
     }
 
     /**

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableEmbeddedComponentModelImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableEmbeddedComponentModelImpl.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableEmbeddedComponentModelImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableEmbeddedComponentModelImpl.java
 Fri Feb 13 18:18:49 2009
@@ -1,4 +1,4 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2009 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.
@@ -17,6 +17,7 @@
 import org.apache.tapestry5.ioc.BaseLocatable;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.Defense;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.model.MutableEmbeddedComponentModel;
 
@@ -38,6 +39,8 @@
 
     private Map<String, String> parameters;
 
+    private List<String> publishedParameters = Collections.emptyList();
+
     /**
      * List of mixin class names.
      */
@@ -122,4 +125,16 @@
     {
         return inheritInformalParameters;
     }
+
+    public void setPublishedParameters(List<String> parameterNames)
+    {
+        Defense.notNull(parameterNames, "parameterNames");
+
+        publishedParameters = parameterNames;
+    }
+
+    public List<String> getPublishedParameters()
+    {
+        return publishedParameters;
+    }
 }

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java?rev=744203&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java
 Fri Feb 13 18:18:49 2009
@@ -0,0 +1,73 @@
+// Copyright 2009 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.tapestry5.internal.pageload;
+
+import org.apache.tapestry5.internal.parser.ComponentTemplate;
+import org.apache.tapestry5.internal.structure.ComponentPageElement;
+import org.apache.tapestry5.internal.structure.Page;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.model.ComponentModel;
+
+/**
+ * Encapsulates a series of actions that are used to assemble a new page 
instance (or a comoponent within the page).
+ */
+interface ComponentAssembler
+{
+    /**
+     * The model defining the component assembled by this assembler.
+     */
+    ComponentModel getModel();
+
+    /**
+     * Assembles and returns page's root component
+     *
+     * @param page to assemble
+     */
+    ComponentPageElement assembleRootComponent(Page page);
+
+    /**
+     * Assembles a component embedded within another component, leaving the 
new component on the {...@link
+     * org.apache.tapestry5.internal.pageload.PageAssembly#createdElement} 
stack.
+     *
+     * @param pageAssembly holds dynamic state while assembling the comopnent
+     * @param embeddedId   the unique id for the component within its container
+     * @param elementName  element name in the template for the component (or 
null if defined via a Tapestry namespaced
+     *                     element)
+     * @param location     location of the embedded component in its 
container's template
+     */
+    void assembleEmbeddedComponent(PageAssembly pageAssembly, String 
embeddedId, String elementName,
+                                   Location location);
+
+    /**
+     * Adds a page assembly action for this component
+     *
+     * @param action to be performed when assembling a page
+     */
+    void add(PageAssemblyAction action);
+
+    /**
+     * Validates that all component ids defined by the model are accounted for 
in the template. In addition, takes care
+     * of id pre-allocation.
+     */
+    void validateEmbeddedIds(ComponentTemplate template);
+
+    /**
+     * Generates an id for an otherwise anonymous component, based on the 
component's type.
+     *
+     * @param componentType
+     * @return unique id based on the type
+     */
+    String generateEmbeddedId(String componentType);
+}

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java?rev=744203&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java
 Fri Feb 13 18:18:49 2009
@@ -0,0 +1,200 @@
+// Copyright 2009 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.tapestry5.internal.pageload;
+
+import org.apache.tapestry5.internal.parser.ComponentTemplate;
+import org.apache.tapestry5.internal.services.Instantiator;
+import org.apache.tapestry5.internal.structure.*;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.IdAllocator;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+import org.apache.tapestry5.model.ComponentModel;
+import org.apache.tapestry5.runtime.RenderCommand;
+
+import java.util.List;
+import java.util.Map;
+
+class ComponentAssemblerImpl implements ComponentAssembler
+{
+    private final Instantiator instantiator;
+
+    private final ComponentPageElementResources resources;
+
+    private final List<PageAssemblyAction> actions = 
CollectionFactory.newList();
+
+    private final IdAllocator allocator = new IdAllocator();
+
+    public ComponentAssemblerImpl(Instantiator instantiator, 
ComponentPageElementResources resources)
+    {
+        this.instantiator = instantiator;
+        this.resources = resources;
+    }
+
+    public ComponentPageElement assembleRootComponent(Page page)
+    {
+        PageAssembly pageAssembly = new PageAssembly(page);
+
+        try
+        {
+            ComponentPageElement newElement = new 
ComponentPageElementImpl(pageAssembly.page, instantiator, resources);
+
+            buildRecursively(pageAssembly, newElement);
+
+            for (PageAssemblyAction action : pageAssembly.deferred)
+            {
+                action.execute(pageAssembly);
+            }
+
+            return pageAssembly.createdElement.peek();
+        }
+        catch (RuntimeException ex)
+        {
+            throw new RuntimeException(String.format("Exception assembling 
root component of page %s: %s",
+                                                     
pageAssembly.page.getLogicalName(),
+                                                     
InternalUtils.toMessage(ex)),
+                                       ex);
+        }
+    }
+
+    public void assembleEmbeddedComponent(PageAssembly pageAssembly, String 
embeddedId, String elementName,
+                                          Location location)
+    {
+        ComponentPageElement container = pageAssembly.activeElement.peek();
+
+        try
+        {
+            ComponentPageElement newElement = container.newChild(embeddedId, 
elementName, instantiator, location);
+
+            buildRecursively(pageAssembly, newElement);
+        }
+        catch (RuntimeException ex)
+        {
+            String message = String.format("Exception assembling embedded 
component '%s' (of type %s, within %s): %s",
+                                           embeddedId,
+                                           
instantiator.getModel().getComponentClassName(),
+                                           container.getCompleteId(),
+                                           InternalUtils.toMessage(ex));
+
+            throw new TapestryException(message, location, ex);
+        }
+    }
+
+    private void buildRecursively(PageAssembly pageAssembly, 
ComponentPageElement newElement)
+    {
+        pageAssembly.page.addLifecycleListener(newElement);
+
+        pushNewElement(pageAssembly, newElement);
+
+        runActions(pageAssembly);
+
+        popNewElement(pageAssembly);
+    }
+
+    private void pushNewElement(PageAssembly pageAssembly, final 
ComponentPageElement componentElement)
+    {
+        // This gets popped after all actions have executed.
+        pageAssembly.activeElement.push(componentElement);
+
+        // The container pops this one.
+        pageAssembly.createdElement.push(componentElement);
+
+        BodyPageElement shunt = new BodyPageElement()
+        {
+            public void addToBody(RenderCommand element)
+            {
+                componentElement.addToTemplate(element);
+            }
+        };
+
+        pageAssembly.bodyElement.push(shunt);
+    }
+
+    private void popNewElement(PageAssembly pageAssembly)
+    {
+        pageAssembly.bodyElement.pop();
+        pageAssembly.activeElement.pop();
+
+        // But the component itself stays on the createdElement stack!
+    }
+
+    private void runActions(PageAssembly pageAssembly)
+    {
+        for (PageAssemblyAction action : actions)
+            action.execute(pageAssembly);
+    }
+
+    public ComponentModel getModel()
+    {
+        return instantiator.getModel();
+    }
+
+    public void add(PageAssemblyAction action)
+    {
+        actions.add(action);
+    }
+
+
+    public void validateEmbeddedIds(ComponentTemplate template)
+    {
+        Map<String, Boolean> embeddedIds = 
CollectionFactory.newCaseInsensitiveMap();
+
+        for (String id : getModel().getEmbeddedComponentIds())
+            embeddedIds.put(id, true);
+
+        for (String id : template.getComponentIds().keySet())
+        {
+            allocator.allocateId(id);
+            embeddedIds.remove(id);
+        }
+
+        if (!embeddedIds.isEmpty())
+        {
+
+            String className = getModel().getComponentClassName();
+
+            throw new RuntimeException(
+                    String.format(
+                            "Embedded component(s) %s are defined within 
component class %s (or a super-class of %s), " +
+                                    "but are not present in the component 
template (%s).",
+                            InternalUtils.joinSorted(embeddedIds.keySet()),
+                            className,
+                            InternalUtils.lastTerm(className),
+                            template.getResource()));
+        }
+    }
+
+    public String generateEmbeddedId(String componentType)
+    {
+        // Component types may be in folders; strip off the folder part for 
starters.
+
+        int slashx = componentType.lastIndexOf("/");
+
+        String baseId = componentType.substring(slashx + 1).toLowerCase();
+
+        // The idAllocator is pre-loaded with all the component ids from the 
template, so even
+        // if the lower-case type matches the id of an existing component, 
there won't be a name
+        // collision.
+
+        return allocator.allocateId(baseId);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("ComponentAssembler[%s]", 
instantiator.getModel().getComponentClassName());
+    }
+}

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/CompositeRenderCommand.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/CompositeRenderCommand.java?rev=744203&r1=744202&r2=744203&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/CompositeRenderCommand.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/CompositeRenderCommand.java
 Fri Feb 13 18:18:49 2009
@@ -1,4 +1,4 @@
-// Copyright 2008 The Apache Software Foundation
+// Copyright 2008, 2009 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.
@@ -23,11 +23,11 @@
  * A RenderCommand wrapper that renders internally a series of render 
commands. This is intended for static content
  * (commands that may write content, but won't affect the render queue itself.
  */
-public class CompositeRenderCommand implements RenderCommand
+class CompositeRenderCommand implements RenderCommand
 {
     /**
      * Composite commands are intended for static elements; elements that 
won't invoke methods on the RenderQueue. To
-     * enforce this, we have a NO-OP version of RenderQueue that is passed ot 
the composed render commands.
+     * enforce this, we have a NO-OP version of RenderQueue that is passed to 
the composed render commands.
      */
     private static final RenderQueue NOOP = new RenderQueue()
     {

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java?rev=744203&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java
 Fri Feb 13 18:18:49 2009
@@ -0,0 +1,63 @@
+// Copyright 2009 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.tapestry5.internal.pageload;
+
+import org.apache.tapestry5.Binding;
+import org.apache.tapestry5.model.ComponentModel;
+
+/**
+ * Encapsulates logic related to assembling an embedded component within a 
{...@link org.apache.tapestry5.internal.pageload.ComponentAssembler}.
+ */
+interface EmbeddedComponentAssembler
+{
+    void addInstanceMixin(ComponentModel mixinModel);
+
+    /**
+     * Creates a binder that can later be used to bind the parameter. The 
parameter name may be unqualified ("value") or
+     * have a mixin prefix ("mymixin.value").  In the former case, the correct 
mixin is located (though the more typical
+     * case is to bind a parameter of the component itself, not a parameter of 
a mixin attached to the component). In
+     * the latter case, the mixinId is validated (to ensure it exists).
+     * <p/>
+     * If the name of the parameter does not match a formal parameter of the 
component (or mixin) and the component (or
+     * mixin) does not support informal parameters, then null is returned.
+     *
+     * @param parameterName        simple or qualified parameter name
+     * @param parameterValue       value of parameter (possibly having a 
binding prefix)
+     * @param defaultBindingPrefix default binding prefix to use if the 
parameter is informal
+     * @return object that can bind the parameter once the container and 
component have been instantiated, or null
+     */
+    ParameterBinder createBinder(String parameterName, String parameterValue, 
String defaultBindingPrefix);
+
+    /**
+     * Creates a ParameterBinding where the binding is already instantiated. 
Follows the same logic as {...@link
+     * #createBinder(String, String, String)} in terms of finding the correct 
mixin and parameter name.
+     *
+     * @param parameterName simple or qualified parameter name
+     * @param binding       binding for parameter
+     * @return object that can perform the binding, or null
+     */
+    ParameterBinder createBinder(String parameterName, Binding binding);
+
+    /**
+     * Checks to see if the parameter name  has been bound.
+     */
+    boolean isBound(String parameterName);
+
+    /**
+     * Marks the parameter name as bound. This is necessary to keep template 
bindings from overriding bindings in the
+     * {...@link org.apache.tapestry5.annotations.Component} annotation (even 
inherited bindings).
+     */
+    void setBound(String parameterName);
+}

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java?rev=744203&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
 Fri Feb 13 18:18:49 2009
@@ -0,0 +1,236 @@
+// Copyright 2009 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.tapestry5.internal.pageload;
+
+import org.apache.tapestry5.Binding;
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.internal.services.ComponentInstantiatorSource;
+import org.apache.tapestry5.internal.services.PageElementFactory;
+import org.apache.tapestry5.internal.structure.ComponentPageElement;
+import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
+import org.apache.tapestry5.model.ComponentModel;
+import org.apache.tapestry5.model.ParameterModel;
+
+import java.util.Map;
+
+public class EmbeddedComponentAssemblerImpl implements 
EmbeddedComponentAssembler
+{
+    private final Map<String, ComponentModel> mixinIdToComponentModel = 
CollectionFactory.newCaseInsensitiveMap();
+
+    private final ComponentInstantiatorSource instantiatorSource;
+
+    private final ComponentModel componentModel;
+
+    private final PageElementFactory elementFactory;
+
+    private final Location location;
+
+    private Map<String, Boolean> bound;
+
+    interface BindingCreator
+    {
+        Binding newBinding(String parameterName, ComponentResources 
loadingComponentResources,
+                           ComponentResources embeddedComponentResources, 
String defaultBindingPrefix);
+    }
+
+    public EmbeddedComponentAssemblerImpl(ComponentInstantiatorSource 
instantiatorSource,
+                                          PageElementFactory elementFactory,
+                                          String componentClassName,
+                                          Location location)
+    {
+        this.instantiatorSource = instantiatorSource;
+        this.elementFactory = elementFactory;
+        this.location = location;
+
+        componentModel = getModel(componentClassName);
+
+        // Add the implementation mixins defined by the component model.
+
+        for (String className : componentModel.getMixinClassNames())
+        {
+            addInstanceMixin(getModel(className));
+        }
+
+        // Instance mixins will be added later.
+    }
+
+    private ComponentModel getModel(String className)
+    {
+        return instantiatorSource.getInstantiator(className).getModel();
+    }
+
+    public void addInstanceMixin(ComponentModel mixinModel)
+    {
+        String mixinId = 
InternalUtils.lastTerm(mixinModel.getComponentClassName());
+
+        // TODO: Check for conflicts here?
+
+        mixinIdToComponentModel.put(mixinId, mixinModel);
+    }
+
+    public ParameterBinder createBinder(String parameterName, final String 
parameterValue, String defaultBindingPrefix)
+    {
+        BindingCreator creator = new BindingCreator()
+        {
+            public Binding newBinding(String parameterName, ComponentResources 
loadingComponentResources,
+                                      ComponentResources 
embeddedComponentResources, String defaultBindingPrefix)
+            {
+                return elementFactory.newBinding(parameterName, 
loadingComponentResources, embeddedComponentResources,
+                                                 defaultBindingPrefix, 
parameterValue, location);
+            }
+        };
+
+
+        return createBinder(parameterName, defaultBindingPrefix, creator);
+    }
+
+    public ParameterBinder createBinder(String parameterName, final Binding 
binding)
+    {
+        BindingCreator creator = new BindingCreator()
+        {
+            public Binding newBinding(String parameterName, ComponentResources 
loadingComponentResources,
+                                      ComponentResources 
embeddedComponentResources, String defaultBindingPrefix)
+            {
+                return binding;
+            }
+        };
+
+        return createBinder(parameterName, null, creator);
+    }
+
+
+    private ParameterBinder createBinder(String parameterName, String 
defaultBindingPrefix,
+                                         BindingCreator creator)
+    {
+        int dotx = parameterName.indexOf('.');
+
+        if (dotx > 0)
+            return createQualifiedParameterBinder(parameterName.substring(0, 
dotx),
+                                                  parameterName.substring(dotx 
+ 1),
+                                                  defaultBindingPrefix,
+                                                  creator);
+
+        // OK, see if its a parameter of the component (that takes precedence).
+
+        ParameterModel pmodel = 
componentModel.getParameterModel(parameterName);
+
+        if (pmodel != null)
+            return createBinder(null, parameterName, 
pmodel.getDefaultBindingPrefix(), creator);
+
+        String informalMixinId = null;
+
+        for (Map.Entry<String, ComponentModel> me : 
mixinIdToComponentModel.entrySet())
+        {
+            String mixinId = me.getKey();
+            ComponentModel model = me.getValue();
+
+            if (informalMixinId == null && 
model.getSupportsInformalParameters())
+                informalMixinId = mixinId;
+
+            pmodel = model.getParameterModel(parameterName);
+
+            if (pmodel != null)
+                return createBinder(mixinId, parameterName, 
pmodel.getDefaultBindingPrefix(), creator);
+        }
+
+        // OK, it doesn't match any formal parameter of the component or any 
mixin.
+
+        // If neither the component nor any of its mixins supports informal 
parameters,
+        // then return null to ignore the parameter.
+
+        if (informalMixinId == null && 
!componentModel.getSupportsInformalParameters()) return null;
+
+        // Add as an informal parameter either to a mixin (if an mixin 
supprting informatl parameters
+        // was found) or to the component itself (otherwise).
+
+        return createBinder(informalMixinId, parameterName, 
defaultBindingPrefix, creator);
+    }
+
+    private ParameterBinder createQualifiedParameterBinder(String mixinId, 
String parameterName,
+                                                           String 
defaultBindingPrefix,
+                                                           BindingCreator 
creator)
+    {
+        ComponentModel mixinModel = mixinIdToComponentModel.get(mixinId);
+
+        if (mixinModel == null)
+        {
+            String message = String.format(
+                    "Parameter '%s.%s' does not match any defined mixins for 
this component.  Available mixins: %s.",
+                    mixinId, parameterName,
+                    InternalUtils.sortedKeys(mixinIdToComponentModel));
+
+            throw new TapestryException(message, location, null);
+        }
+
+        return createBinder(mixinId, mixinModel, parameterName, 
defaultBindingPrefix, creator);
+    }
+
+    private ParameterBinder createBinder(String mixinId,
+                                         ComponentModel model,
+                                         String parameterName,
+                                         String defaultBindingPrefix,
+                                         BindingCreator creator)
+    {
+        ParameterModel pmodel = model.getParameterModel(parameterName);
+
+        // Ignore informal parameters for mixins that don't support them.
+
+        if (pmodel == null && !model.getSupportsInformalParameters())
+            return null;
+
+        final String bindingPrefix = pmodel == null ? defaultBindingPrefix : 
pmodel.getDefaultBindingPrefix();
+
+        return createBinder(mixinId, parameterName, bindingPrefix, creator);
+    }
+
+    private ParameterBinder createBinder(final String mixinId,
+                                         final String parameterName,
+                                         final String defaultBindingPrefix,
+                                         final BindingCreator creator)
+    {
+        return new ParameterBinder()
+        {
+            public void bind(ComponentPageElement container, 
ComponentPageElement embedded)
+            {
+                Binding binding =
+                        creator.newBinding(parameterName,
+                                           container.getComponentResources(),
+                                           embedded.getComponentResources(),
+                                           defaultBindingPrefix);
+
+                if (mixinId == null)
+                    embedded.bindParameter(parameterName, binding);
+                else
+                    embedded.bindMixinParameter(mixinId, parameterName, 
binding);
+            }
+        };
+    }
+
+    public boolean isBound(String parameterName)
+    {
+        return InternalUtils.get(bound, parameterName) != null;
+    }
+
+    public void setBound(String parameterName)
+    {
+        if (bound == null)
+            bound = CollectionFactory.newCaseInsensitiveMap();
+
+        bound.put(parameterName, true);
+    }
+}

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java?rev=744203&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java
 Fri Feb 13 18:18:49 2009
@@ -0,0 +1,116 @@
+// Copyright 2009 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.tapestry5.internal.pageload;
+
+import org.apache.tapestry5.internal.structure.BodyPageElement;
+import org.apache.tapestry5.internal.structure.ComponentPageElement;
+import org.apache.tapestry5.internal.structure.Page;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.util.Stack;
+import org.apache.tapestry5.runtime.RenderCommand;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Mutable data used when {...@link 
org.apache.tapestry5.internal.pageload.ComponentAssembler}s are assembling a 
page
+ * instance.
+ */
+class PageAssembly
+{
+    public final Page page;
+
+    public final Stack<ComponentPageElement> activeElement = 
CollectionFactory.newStack();
+
+    public final Stack<BodyPageElement> bodyElement = 
CollectionFactory.newStack();
+
+    public final Stack<ComponentPageElement> createdElement = 
CollectionFactory.newStack();
+
+    public final Stack<EmbeddedComponentAssembler> embeddedAssembler = 
CollectionFactory.newStack();
+
+    public final List<PageAssemblyAction> deferred = 
CollectionFactory.newList();
+
+    private final List<RenderCommand> composableRenderCommands = 
CollectionFactory.newList();
+
+    private final Set<String> flags = CollectionFactory.newSet();
+
+    PageAssembly(Page page)
+    {
+        this.page = page;
+    }
+
+    /**
+     * Adds the command to the top element of the {...@link #bodyElement} 
stack. {...@linkplain
+     * #flushComposableRenderCommands() Flushes} composable render commands 
first.
+     *
+     * @param command
+     */
+    public void addRenderCommand(RenderCommand command)
+    {
+        flushComposableRenderCommands();
+
+        bodyElement.peek().addToBody(command);
+    }
+
+    /**
+     * Adds the command to the list of composable commands. Composable 
commands are added to the top element of the body
+     * element stack when {...@linkplain #flushComposableRenderCommands() 
flushed}.
+     *
+     * @param command
+     */
+    public void addComposableRenderCommand(RenderCommand command)
+    {
+        composableRenderCommands.add(command);
+    }
+
+    /**
+     * Adds any composed render commands to the top element of the bodyElement 
stack. Render commands may be combined as
+     * a {...@link 
org.apache.tapestry5.internal.pageload.CompositeRenderCommand}.
+     */
+    public void flushComposableRenderCommands()
+    {
+        int count = composableRenderCommands.size();
+
+        switch (count)
+        {
+            case 0:
+                break;
+
+            case 1:
+                bodyElement.peek().addToBody(composableRenderCommands.get(0));
+                break;
+
+            default:
+                RenderCommand[] commands = 
composableRenderCommands.toArray(new RenderCommand[count]);
+
+                bodyElement.peek().addToBody(new 
CompositeRenderCommand(commands));
+                break;
+        }
+
+        composableRenderCommands.clear();
+    }
+
+    public boolean checkAndSetFlag(String flagName)
+    {
+        boolean result = flags.contains(flagName);
+
+        if (!result)
+            flags.add(flagName);
+
+        return result;
+    }
+}
+
+

Added: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssemblyAction.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssemblyAction.java?rev=744203&view=auto
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssemblyAction.java
 (added)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssemblyAction.java
 Fri Feb 13 18:18:49 2009
@@ -0,0 +1,25 @@
+// Copyright 2009 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.tapestry5.internal.pageload;
+
+interface PageAssemblyAction
+{
+    /**
+     * Execute some action related to assembling a page.
+     *
+     * @param pageAssembly identifies the page being assembled
+     */
+    void execute(PageAssembly pageAssembly);
+}


Reply via email to