You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2009/02/15 05:44:14 UTC
svn commit: r744608 [1/2] - in /tapestry/tapestry5/trunk: src/site/apt/
src/site/apt/guide/ tapestry-core/src/main/java/org/apache/tapestry5/
tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/
tapestry-core/src/main/java/org/apache/ta...
Author: hlship
Date: Sun Feb 15 04:44:12 2009
New Revision: 744608
URL: http://svn.apache.org/viewvc?rev=744608&view=rev
Log:
TAP5-487: Easier way to expose parameters of an embedded component in a containing component
Added:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerSource.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentName.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/ParameterBinderImpl.java
- copied, changed from r744203, tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ParameterBinder.java
tapestry/tapestry5/trunk/tapestry-core/src/test/app1/PublishParametersDemo.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Publish1.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Publish2.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/components/Publish3.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/PublishParametersDemo.java
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/Publish1.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/Publish2.tml
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app1/components/Publish3.tml
Removed:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/InheritedBinding.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/InheritedBindingTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/ComponentPageElementImplTest.java
Modified:
tapestry/tapestry5/trunk/src/site/apt/guide/parameters.apt
tapestry/tapestry5/trunk/src/site/apt/index.apt
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResourcesCommon.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.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/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/PageLoaderImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/LinkSourceImpl.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/services/PageLoader.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PagePoolImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServicesMessages.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/Page.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/PageImpl.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/structure/StructureMessages.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/services/ServicesStrings.properties
tapestry/tapestry5/trunk/tapestry-core/src/main/resources/org/apache/tapestry5/internal/structure/StructureStrings.properties
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/IntegrationTests.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/ActionViaLinkDemo.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.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/services/LinkSourceImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PageElementFactoryImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/PagePoolImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/structure/PageImplTest.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/test/InternalBaseTestCase.java
Modified: tapestry/tapestry5/trunk/src/site/apt/guide/parameters.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/guide/parameters.apt?rev=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/guide/parameters.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/guide/parameters.apt Sun Feb 15 04:44:12 2009
@@ -486,4 +486,24 @@
builds around your class. In any case, once the resources are injected,
they can be queried.
-
\ No newline at end of file
+Publishing Parameters
+
+ Often when creating new components from existing components, you want to expose some of the
+ functionality of the embedded component, in the form of exposing parameters of the embedded components
+ as parameters of the outer component.
+
+ In Tapestry 5.0, you would define a parameter of the outer component, and use the
+ "inherit:" binding prefix to connect the inner component's parameter to the outer component's parameter.
+ This is somewhat clumsy, as it involves creating an otherwise unused field just for the parameter; in practice
+ it also leads to duplication of the documentation of the parameter.
+
+ In Tapestry 5.1, you may use the publishParameters attribute of the
+ {{{../../apidocs/org/apache/tapestry5/annotations/Component.html}Component}}} annotation. List one
+ or more parameters seperated by commas: those parameters of the inner/embedded component become
+ parameters of the outer component. You should not define a parameter field in the outer component.
+
+ There are still cases where you want to use the "inherit:" binding prefix. For example, if you have
+ several components that need to share a parameter, then you must do it the Tapestry 5.0 way: a true parameter
+ on the outer component, and "inherit:" bindings on the embedded components. You can follow a similar pattern
+ to rename a parameter in the outer component.
+
Modified: tapestry/tapestry5/trunk/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/src/site/apt/index.apt?rev=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/src/site/apt/index.apt (original)
+++ tapestry/tapestry5/trunk/src/site/apt/index.apt Sun Feb 15 04:44:12 2009
@@ -32,6 +32,33 @@
Tapestry is released under the Apache Software Licence 2.0.
+New And Of Note
+
+ * Some significant performance improvements over Tapestry 5.0.18: the time to initially load a page,
+ and the time to render a page have decreased.
+
+ * Tapestry IoC services can now be easily <{{{tapestry-ioc/advice.html}advised}}> as well as
+ <{{{tapestry-ioc/decorator.html}decorated}}> (both of these refer to Aspect Oriented Techniques applied to
+ Tapestry IoC services).
+
+ * Tapestry Services can now be injected into Spring Beans, when using the Tapestry/Spring integration library.
+
+ * Tapestry now {{{guide/compress.html}compresses}} responses for clients that support compression.
+ Context and classpath assets
+ are now handled uniformly: versioned URLs, far-future expiration headers, and GZIP compression where applicable.
+
+ * Ordered and mapped configurations can now have overrides.
+
+ * Property expressions have been improved: You can now invoke methods with parameters, or create a list (very useful for link contexts).
+
+ * IoC Service contributions may now be made in terms of classes (that are automatically instantiated) as well as
+ instances.
+
+ * A simpler method of {{{apidocs/org/apache/tapestry5/ioc/services/ServiceOverride}overriding built-in services}}
+ has been added.
+
+ []
+
Roadmap
Now that that 5.0 release is <finally> out and available, work is starting on a 5.1 release.
@@ -79,29 +106,7 @@
| {{{http://code.google.com/p/tapestry5-treegrid/}tapestry5-treegrid}} | Gabriel Landais | Combination tree navigation and data grid, based on sstree. |
*--+--+--+
-New And Of Note
-
- * Tapestry IoC services can now be easily <{{{tapestry-ioc/advice.html}advised}}> as well as
- <{{{tapestry-ioc/decorator.html}decorated}}> (both of these refer to Aspect Oriented Techniques applied to
- Tapestry IoC services).
-
- * Tapestry Services can now be injected into Spring Beans, when using the Tapestry/Spring integration library.
-
- * Tapestry now {{{guide/compress.html}compresses}} responses for clients that support compression.
- Context and classpath assets
- are now handled uniformly: versioned URLs, far-future expiration headers, and GZIP compression where applicable.
- * Ordered and mapped configurations can now have overrides.
-
- * Property expressions have been improved: You can now invoke methods with parameters, or create a list (very useful for link contexts).
-
- * IoC Service contributions may now be made in terms of classes (that are automatically instantiated) as well as
- instances.
-
- * A simpler method of {{{apidocs/org/apache/tapestry5/ioc/services/ServiceOverride}overriding built-in services}}
- has been added.
-
- []
Adaptive API
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResourcesCommon.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResourcesCommon.java?rev=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResourcesCommon.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/ComponentResourcesCommon.java Sun Feb 15 04:44:12 2009
@@ -34,15 +34,14 @@
/**
* Return a string consisting the concatinated ids of all containing components, separated by periods. In addition,
- * nested ids are always all lower case. I.e., "foo.bar.baz". Returns null for the root component of a page.
+ * nested ids are always all lower case. I.e., "foo.bar.baz". Returns null for the root component of a page.
*/
String getNestedId();
/**
* Returns a string consisting of the logical name of the containing page, and the {@link #getNestedId() nested id}
- * of this component, separated by a colon. I.e., "MyPage:foo.bar.baz". For a page, returns just the page's logical
- * name.
+ * of this component, separated by a colon. I.e., "MyPage:foo.bar.baz". For a page, returns just the page's name.
* <p/>
* This value is often used to obtain an equivalent component instance in a later request.
*
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.java?rev=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/BeanEditForm.java Sun Feb 15 04:44:12 2009
@@ -45,14 +45,6 @@
@SupportsInformalParameters
public class BeanEditForm implements ClientElement, FormValidationControl
{
- /**
- * If true (the default), then the JavaScript will be added to position the cursor into the form. The field to
- * receive focus is the first rendered field that is in error, or required, or present (in that order of priority).
- *
- * @see org.apache.tapestry5.corelib.components.Form#autofocus
- */
- @Parameter
- private boolean autofocus;
/**
* The text label for the submit button of the form, by default "Create/Update".
@@ -103,23 +95,8 @@
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String reorder;
- /**
- * May be bound, to override the Form's default for clientValidation.
- */
- @Parameter
- private boolean clientValidation;
-
- /**
- * Binding the zone parameter will cause the form submission to be handled as an Ajax request that updates the
- * indicated zone. Often a BeanEditForm will update the same zone that contains it.
- */
- @Parameter(defaultPrefix = BindingConstants.LITERAL)
- private String zone;
-
- @Component(parameters = { "clientValidation=inherit:clientValidation",
- "validationId=componentResources.id",
- "autofocus=inherit:autofocus",
- "zone=inherit:zone" })
+ @Component(parameters =
+ "validationId=componentResources.id", publishParameters = "clientValidation,autofocus,zone")
private Form form;
/**
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java?rev=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/corelib/components/Grid.java Sun Feb 15 04:44:12 2009
@@ -41,8 +41,7 @@
* editing properties of each row. This is currently workable but less than ideal -- if the order of rows provided by
* the {@link org.apache.tapestry5.grid.GridDataSource} changes between render and form submission, then there's the
* possibility that data will be applied to the wrong server-side objects. In general, when using Grid and Form
- * together, you want to provide the Grid with a {@link org.apache.tapestry5.PrimaryKeyEncoder} (via the encoder
- * parameter).
+ * together, you want to provide the Grid with a {@link org.apache.tapestry5.ValueEncoder} (via the encoder parameter).
*
* @see org.apache.tapestry5.beaneditor.BeanModel
* @see org.apache.tapestry5.services.BeanModelSource
@@ -89,13 +88,7 @@
private Object row;
/**
- * Optional output parameter used to identify the index (from zero) of the row being rendered.
- */
- @Parameter
- private int rowIndex;
-
- /**
- * Optional output parmater used to identify the index of the column being rendered.
+ * Optional output parmeter used to identify the index of the column being rendered.
*/
@Parameter
private int columnIndex;
@@ -161,31 +154,6 @@
@Parameter(value = "block:empty", defaultPrefix = BindingConstants.LITERAL)
private Block empty;
-
- /**
- * If true, then the CSS class on each <TD> and <TH> cell will be omitted, which can reduce the amount
- * of output from the component overall by a considerable amount. Leave this as false, the default, when you are
- * leveraging the CSS to customize the look and feel of particular columns.
- */
- @Parameter
- private boolean lean;
-
- /**
- * If true and the Grid is enclosed by a Form, then the normal state persisting logic is turned off. Defaults to
- * false, enabling state persisting within Forms. If a Grid is present for some reason within a Form, but does not
- * contain any form control components (such as {@link TextField}), then binding volatile to false will reduce the
- * amount of client-side state that must be persisted.
- */
- @Parameter(name = "volatile")
- private boolean volatileState;
-
- /**
- * The CSS class for the tr element for each data row. This can be used to highlight particular rows, or cycle
- * between CSS values (for the "zebra effect"). If null or not bound, then no particular CSS class value is used.
- */
- @Parameter(cache = false)
- private String rowClass;
-
/**
* CSS class for the <table> element. In addition, informal parameters to the Grid are rendered in the table
* element.
@@ -203,14 +171,6 @@
private boolean inPlace;
/**
- * Changes how state is recorded into the form to store the {@linkplain org.apache.tapestry5.ValueEncoder#toClient(Object)
- * client value} for each row (rather than the index), and restore the {@linkplain
- * org.apache.tapestry5.ValueEncoder#toValue(String)row values} from the client value.
- */
- @Parameter
- private ValueEncoder encoder;
-
- /**
* The name of the psuedo-zone that encloses the Grid.
*/
@Property(write = false)
@@ -247,16 +207,12 @@
@Component(
parameters = {
- "rowIndex=inherit:rowIndex",
"columnIndex=inherit:columnIndex",
- "rowClass=inherit:rowClass",
"rowsPerPage=rowsPerPage",
"currentPage=currentPage",
"row=row",
- "overrides=overrides",
- "volatile=inherit:volatile",
- "encoder=inherit:encoder",
- "lean=inherit:lean" })
+ "overrides=overrides" },
+ publishParameters = "rowIndex,rowClass,volatile,encoder,lean")
private GridRows rows;
@Component(parameters = {
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=744608&r1=744607&r2=744608&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 Sun Feb 15 04:44:12 2009
@@ -14,7 +14,6 @@
package org.apache.tapestry5.internal;
-import org.apache.commons.codec.binary.Base64;
import org.apache.tapestry5.*;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.Resource;
@@ -25,7 +24,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
@@ -45,6 +43,8 @@
private static final int BUFFER_SIZE = 5000;
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
/**
* Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
* characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
@@ -389,8 +389,8 @@
*/
public static String[] splitAtCommas(String value)
{
- if (value == null)
- return new String[0];
+ if (InternalUtils.isBlank(value))
+ return EMPTY_STRING_ARRAY;
return COMMA_PATTERN.split(value.trim());
}
@@ -421,26 +421,6 @@
out.flush();
}
- /**
- * Encodes a long in Base64. Strips off the trailing "=" padding characters (if present).
- *
- * @param input value to encode
- * @return encoded as Base64
- * @since 5.1.1.0
- */
- public static String toBase64(long input)
- {
- BigInteger big = new BigInteger(Long.toString(input));
-
- byte[] encoded = Base64.encodeBase64(big.toByteArray());
-
- String asString = new String(encoded);
-
- int lastx = asString.indexOf('=');
-
- return lastx > 0 ? asString.substring(0, lastx) : asString;
- }
-
public static boolean isEqual(EventContext left, EventContext right)
{
if (left == right) return true;
Modified: 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=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssembler.java Sun Feb 15 04:44:12 2009
@@ -19,6 +19,7 @@
import org.apache.tapestry5.internal.structure.Page;
import org.apache.tapestry5.ioc.Location;
import org.apache.tapestry5.model.ComponentModel;
+import org.apache.tapestry5.model.EmbeddedComponentModel;
/**
* Encapsulates a series of actions that are used to assemble a new page instance (or a comoponent within the page).
@@ -41,13 +42,15 @@
* 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
+ * @param pageAssembly holds dynamic state while assembling the comopnent
+ * @param embeddedAssembler
+ * @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,
+ void assembleEmbeddedComponent(PageAssembly pageAssembly, EmbeddedComponentAssembler embeddedAssembler,
+ String embeddedId, String elementName,
Location location);
/**
@@ -70,4 +73,32 @@
* @return unique id based on the type
*/
String generateEmbeddedId(String componentType);
+
+ /**
+ * Creates an assembler for an embedded component within this component. Does some additional tracking of published
+ * parameters.
+ *
+ * @param embeddedId unique id for the embedded component
+ * @param componentClassName class name to instantiate
+ * @param embeddedModel model defining how the component is used (may be null)
+ * @param mixins mixins for the component (as defined in the template)
+ * @param location location of the component (i.e., it's location in the container template)
+ * @return assembler for the component
+ */
+ EmbeddedComponentAssembler createEmbeddedAssembler(String embeddedId, String componentClassName,
+ EmbeddedComponentModel embeddedModel,
+ String mixins,
+ Location location);
+
+ /**
+ * Finds a binder for a published parameter, or returns null. That is, if the parameter name matches the name of a
+ * parameter of an emebdded components of this component, returns a parameter binder for the parameter. The caller
+ * will pass the {@link org.apache.tapestry5.internal.structure.ComponentPageElement} that corresponds to this
+ * component to the binder and the binder will, internally, redirect to the correct embedded ComponentPageElement.
+ *
+ * @param parameterName simple (unqualified) name of parameter
+ * @return binder, or null if the parameter name does not correspond to a published parameter of an embedded
+ * component
+ */
+ ParameterBinder getBinder(String parameterName);
}
Modified: 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=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerImpl.java Sun Feb 15 04:44:12 2009
@@ -14,7 +14,9 @@
package org.apache.tapestry5.internal.pageload;
+import org.apache.tapestry5.Binding;
import org.apache.tapestry5.internal.parser.ComponentTemplate;
+import org.apache.tapestry5.internal.services.ComponentInstantiatorSource;
import org.apache.tapestry5.internal.services.Instantiator;
import org.apache.tapestry5.internal.structure.*;
import org.apache.tapestry5.ioc.Location;
@@ -23,25 +25,51 @@
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.EmbeddedComponentModel;
import org.apache.tapestry5.runtime.RenderCommand;
+import org.apache.tapestry5.services.ComponentClassResolver;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
class ComponentAssemblerImpl implements ComponentAssembler
{
+ private final ComponentAssemblerSource assemblerSource;
+
+ private final ComponentInstantiatorSource instantiatorSource;
+
+ private final ComponentClassResolver componentClassResolver;
+
private final Instantiator instantiator;
+ private final Locale locale;
+
private final ComponentPageElementResources resources;
private final List<PageAssemblyAction> actions = CollectionFactory.newList();
private final IdAllocator allocator = new IdAllocator();
- public ComponentAssemblerImpl(Instantiator instantiator, ComponentPageElementResources resources)
- {
+ private final Map<String, String> publishedParameterToEmbeddedId = CollectionFactory.newCaseInsensitiveMap();
+
+ // Doesn't have to be case-insensitive, because the embeddedIds are always known alues from
+ // publishedParameterToEmbeddedId.
+
+ private final Map<String, String> embeddedIdToComponentClassName = CollectionFactory.newMap();
+
+ public ComponentAssemblerImpl(ComponentAssemblerSource assemblerSource,
+ ComponentInstantiatorSource instantiatorSource,
+ ComponentClassResolver componentClassResolver,
+ Instantiator instantiator,
+ ComponentPageElementResources resources, Locale locale)
+ {
+ this.assemblerSource = assemblerSource;
+ this.instantiatorSource = instantiatorSource;
+ this.componentClassResolver = componentClassResolver;
this.instantiator = instantiator;
this.resources = resources;
+ this.locale = locale;
}
public ComponentPageElement assembleRootComponent(Page page)
@@ -52,7 +80,17 @@
{
ComponentPageElement newElement = new ComponentPageElementImpl(pageAssembly.page, instantiator, resources);
- buildRecursively(pageAssembly, newElement);
+ pageAssembly.componentName.push(new ComponentName(pageAssembly.page.getName()));
+
+ pageAssembly.page.addLifecycleListener(newElement);
+
+ addRootComponentMixins(newElement);
+
+ pushNewElement(pageAssembly, newElement);
+
+ runActions(pageAssembly);
+
+ popNewElement(pageAssembly);
for (PageAssemblyAction action : pageAssembly.deferred)
{
@@ -64,22 +102,54 @@
catch (RuntimeException ex)
{
throw new RuntimeException(String.format("Exception assembling root component of page %s: %s",
- pageAssembly.page.getLogicalName(),
+ pageAssembly.page.getName(),
InternalUtils.toMessage(ex)),
ex);
}
}
- public void assembleEmbeddedComponent(PageAssembly pageAssembly, String embeddedId, String elementName,
+ private void addRootComponentMixins(ComponentPageElement element)
+ {
+ for (String className : instantiator.getModel().getMixinClassNames())
+ {
+ Instantiator mixinInstantiator = instantiatorSource.getInstantiator(className);
+
+ element.addMixin(InternalUtils.lastTerm(className), mixinInstantiator);
+ }
+ }
+
+ public void assembleEmbeddedComponent(PageAssembly pageAssembly, EmbeddedComponentAssembler embeddedAssembler,
+ String embeddedId, String elementName,
Location location)
{
ComponentPageElement container = pageAssembly.activeElement.peek();
try
{
- ComponentPageElement newElement = container.newChild(embeddedId, elementName, instantiator, location);
+ ComponentName containerName = pageAssembly.componentName.peek();
+
+ ComponentName embeddedName = containerName.child(embeddedId.toLowerCase());
+
+ pageAssembly.componentName.push(embeddedName);
+
+ ComponentPageElement newElement = container.newChild(embeddedId,
+ embeddedName.nestedId,
+ embeddedName.completeId,
+ elementName,
+ instantiator,
+ location);
+
+ pageAssembly.page.addLifecycleListener(newElement);
+
+ pushNewElement(pageAssembly, newElement);
+
+ embeddedAssembler.addMixinsToElement(newElement);
+
+ runActions(pageAssembly);
+
+ popNewElement(pageAssembly);
- buildRecursively(pageAssembly, newElement);
+ pageAssembly.componentName.pop();
}
catch (RuntimeException ex)
{
@@ -93,17 +163,6 @@
}
}
- 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.
@@ -192,6 +251,108 @@
return allocator.allocateId(baseId);
}
+ public EmbeddedComponentAssembler createEmbeddedAssembler(String embeddedId, String componentClassName,
+ EmbeddedComponentModel embeddedModel, String mixins,
+ Location location)
+ {
+ EmbeddedComponentAssemblerImpl embedded = new EmbeddedComponentAssemblerImpl(assemblerSource,
+ instantiatorSource,
+ componentClassResolver,
+ componentClassName,
+ locale, embeddedModel,
+ mixins,
+ location);
+
+ if (embeddedModel != null)
+ {
+ ComponentModel embeddedComponentModel = instantiatorSource.getInstantiator(componentClassName).getModel();
+
+ for (String publishedParameterName : embeddedModel.getPublishedParameters())
+ {
+ String existingEmbeddedId = publishedParameterToEmbeddedId.get(publishedParameterName);
+
+ if (existingEmbeddedId != null)
+ {
+ String message = String.format(
+ "Parameter '%s' can not be published by embedded component '%s' as it has already been published by embedded component '%s'.",
+ publishedParameterName, embedded, existingEmbeddedId);
+
+ throw new TapestryException(message, location, null);
+ }
+
+ if (embeddedComponentModel.getParameterModel(publishedParameterName) == null)
+ {
+ String message = String.format(
+ "Component %s does not include a parameter named '%s' to publish. Possible parameters: %s.",
+ componentClassName, publishedParameterName,
+ InternalUtils.joinSorted(embeddedComponentModel.getParameterNames()));
+
+ throw new TapestryException(message, location, null);
+ }
+
+ publishedParameterToEmbeddedId.put(publishedParameterName, embeddedId);
+ }
+
+ }
+
+ embeddedIdToComponentClassName.put(embeddedId, componentClassName);
+
+ return embedded;
+ }
+
+ public ParameterBinder getBinder(final String parameterName)
+ {
+ final String embeddedId = publishedParameterToEmbeddedId.get(parameterName);
+
+ if (embeddedId == null) return null;
+
+ String componentClassName = embeddedIdToComponentClassName.get(embeddedId);
+
+ final ComponentAssembler embeddedAssembler = assemblerSource.getAssembler(componentClassName, locale);
+
+ final ParameterBinder embeddedBinder = embeddedAssembler.getBinder(parameterName);
+
+ // The complex case: a re-publish! Yes you can go deep here if you don't
+ // value your sanity!
+
+ if (embeddedBinder != null)
+ {
+ return new ParameterBinder()
+ {
+ public void bind(ComponentPageElement element, Binding binding)
+ {
+ ComponentPageElement subelement = element.getEmbeddedElement(embeddedId);
+
+ embeddedBinder.bind(subelement, binding);
+ }
+
+ public String getDefaultBindingPrefix(String metaDefault)
+ {
+ return embeddedBinder.getDefaultBindingPrefix(metaDefault);
+ }
+ };
+ }
+
+ // The simple case, publishing a parameter of a subcomponent as if it were a parameter
+ // of this component.
+
+ return new ParameterBinder()
+ {
+ public void bind(ComponentPageElement element, Binding binding)
+ {
+ ComponentPageElement subelement = element.getEmbeddedElement(embeddedId);
+
+ subelement.bindParameter(parameterName, binding);
+ }
+
+ public String getDefaultBindingPrefix(String metaDefault)
+ {
+ return embeddedAssembler.getModel().getParameterModel(parameterName).getDefaultBindingPrefix();
+ }
+ };
+ }
+
+
@Override
public String toString()
{
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerSource.java?rev=744608&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerSource.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentAssemblerSource.java Sun Feb 15 04:44:12 2009
@@ -0,0 +1,29 @@
+// 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 java.util.Locale;
+
+/**
+ * Provides access to {@link org.apache.tapestry5.internal.pageload.ComponentAssembler}s (this is used by the assemblers
+ * to find related assemblers).
+ */
+public interface ComponentAssemblerSource
+{
+ /**
+ * Gets (and possibly creates) a component assembler for the indicated class name and locale.
+ */
+ public ComponentAssembler getAssembler(String className, Locale locale);
+}
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentName.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentName.java?rev=744608&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentName.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ComponentName.java Sun Feb 15 04:44:12 2009
@@ -0,0 +1,50 @@
+// 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;
+
+/**
+ * Used to construct component names.
+ */
+public class ComponentName
+{
+ private final String pageName;
+
+ final String nestedId;
+
+ final String completeId;
+
+ ComponentName(String pageName)
+ {
+ this.pageName = pageName;
+ this.nestedId = null;
+ this.completeId = pageName;
+ }
+
+ private ComponentName(String pageName, String nestedId, String completeId)
+ {
+ this.completeId = completeId;
+ this.nestedId = nestedId;
+ this.pageName = pageName;
+ }
+
+ ComponentName child(String embeddedId)
+ {
+ String newNestedId = nestedId == null
+ ? embeddedId
+ : nestedId + "." + embeddedId;
+
+ return new ComponentName(pageName, newNestedId, pageName + ":" + newNestedId);
+ }
+}
Modified: 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=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssembler.java Sun Feb 15 04:44:12 2009
@@ -14,16 +14,14 @@
package org.apache.tapestry5.internal.pageload;
-import org.apache.tapestry5.Binding;
-import org.apache.tapestry5.model.ComponentModel;
+import org.apache.tapestry5.internal.structure.ComponentPageElement;
+import org.apache.tapestry5.ioc.Locatable;
/**
* Encapsulates logic related to assembling an embedded component within a {@link org.apache.tapestry5.internal.pageload.ComponentAssembler}.
*/
-interface EmbeddedComponentAssembler
+interface EmbeddedComponentAssembler extends Locatable
{
- 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
@@ -32,23 +30,14 @@
* <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.
+ * <p/>
+ * This method should only be called at page-assembly time as it requires some data that is collected during
+ * ComponentAssembly construction in order to handle published parameters of embedded components.
*
* @param parameterName simple or qualified parameter name
- * @param binding binding for parameter
- * @return object that can perform the binding, or null
+ * @return object that can bind the parameter
*/
- ParameterBinder createBinder(String parameterName, Binding binding);
+ ParameterBinder createParameterBinder(String parameterName);
/**
* Checks to see if the parameter name has been bound.
@@ -60,4 +49,12 @@
* {@link org.apache.tapestry5.annotations.Component} annotation (even inherited bindings).
*/
void setBound(String parameterName);
+
+
+ /**
+ * Adds mixins to the newly created embedded element.
+ *
+ * @param newElement new element requiring mixins
+ */
+ void addMixinsToElement(ComponentPageElement newElement);
}
Modified: 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=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java Sun Feb 15 04:44:12 2009
@@ -14,47 +14,68 @@
package org.apache.tapestry5.internal.pageload;
-import org.apache.tapestry5.Binding;
-import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.internal.TapestryInternalUtils;
import org.apache.tapestry5.internal.services.ComponentInstantiatorSource;
-import org.apache.tapestry5.internal.services.PageElementFactory;
+import org.apache.tapestry5.internal.services.Instantiator;
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 org.apache.tapestry5.model.EmbeddedComponentModel;
+import org.apache.tapestry5.services.ComponentClassResolver;
+import java.util.Locale;
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 ComponentAssemblerSource assemblerSource;
- private final PageElementFactory elementFactory;
+ private final Locale locale;
+
+ private final ComponentModel componentModel;
private final Location location;
- private Map<String, Boolean> bound;
+ private final Map<String, ComponentModel> mixinIdToComponentModel = CollectionFactory.newCaseInsensitiveMap();
- interface BindingCreator
- {
- Binding newBinding(String parameterName, ComponentResources loadingComponentResources,
- ComponentResources embeddedComponentResources, String defaultBindingPrefix);
- }
+ /**
+ * Maps parameter names (both simple, and qualified with the mixin id) to the corresponding QualifiedParameterName.
+ */
+ private final Map<String, ParameterBinder> parameterNameToBinder = CollectionFactory.newCaseInsensitiveMap();
+
+ // The id of the mixin to receive informal parameters. If null, the component itself recieves them.
+ // If the component doesn't support them, they are quietly dropped.
- public EmbeddedComponentAssemblerImpl(ComponentInstantiatorSource instantiatorSource,
- PageElementFactory elementFactory,
+ private final String informalParametersMixinId;
+
+ private Map<String, Boolean> bound;
+
+ /**
+ * @param assemblerSource
+ * @param instantiatorSource used to access component models
+ * @param componentClassResolver used to convert mixin types to component models
+ * @param componentClassName class name of embedded component
+ * @param locale
+ * @param embeddedModel embedded model (may be null for components defined in the template)
+ * @param templateMixins list of mixins from the t:mixins element (possibly null)
+ * @param location location of components element in its container's template
+ */
+ public EmbeddedComponentAssemblerImpl(ComponentAssemblerSource assemblerSource,
+ ComponentInstantiatorSource instantiatorSource,
+ ComponentClassResolver componentClassResolver,
String componentClassName,
+ Locale locale, EmbeddedComponentModel embeddedModel,
+ String templateMixins,
Location location)
{
+ this.assemblerSource = assemblerSource;
this.instantiatorSource = instantiatorSource;
- this.elementFactory = elementFactory;
+ this.locale = locale;
this.location = location;
componentModel = getModel(componentClassName);
@@ -63,162 +84,136 @@
for (String className : componentModel.getMixinClassNames())
{
- addInstanceMixin(getModel(className));
+ addMixin(className);
}
- // Instance mixins will be added later.
- }
-
- private ComponentModel getModel(String className)
- {
- return instantiatorSource.getInstantiator(className).getModel();
- }
+ // If there's an embedded model (i.e., there was an @Component annotation)
+ // then it may define some mixins.
- 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()
+ if (embeddedModel != null)
{
- public Binding newBinding(String parameterName, ComponentResources loadingComponentResources,
- ComponentResources embeddedComponentResources, String defaultBindingPrefix)
+ for (String className : embeddedModel.getMixinClassNames())
{
- return elementFactory.newBinding(parameterName, loadingComponentResources, embeddedComponentResources,
- defaultBindingPrefix, parameterValue, location);
+ addMixin(className);
}
- };
-
+ }
- return createBinder(parameterName, defaultBindingPrefix, creator);
- }
+ // And the template may include a t:mixins element to define yet more mixin.
- public ParameterBinder createBinder(String parameterName, final Binding binding)
- {
- BindingCreator creator = new BindingCreator()
+ for (String mixinType : TapestryInternalUtils.splitAtCommas(templateMixins))
{
- public Binding newBinding(String parameterName, ComponentResources loadingComponentResources,
- ComponentResources embeddedComponentResources, String defaultBindingPrefix)
- {
- return binding;
- }
- };
+ String className = componentClassResolver.resolveMixinTypeToClassName(mixinType);
- return createBinder(parameterName, null, creator);
- }
+ addMixin(className);
+ }
+ informalParametersMixinId = prescanMixins();
- private ParameterBinder createBinder(String parameterName, String defaultBindingPrefix,
- BindingCreator creator)
+ }
+
+ private String prescanMixins()
{
- int dotx = parameterName.indexOf('.');
+ String supportsInformals = null;
- if (dotx > 0)
- return createQualifiedParameterBinder(parameterName.substring(0, dotx),
- parameterName.substring(dotx + 1),
- defaultBindingPrefix,
- creator);
+ for (Map.Entry<String, ComponentModel> entry : mixinIdToComponentModel.entrySet())
+ {
+ String mixinId = entry.getKey();
+ ComponentModel mixinModel = entry.getValue();
- // OK, see if its a parameter of the component (that takes precedence).
+ updateParameterNameToQualified(mixinId, mixinModel);
- ParameterModel pmodel = componentModel.getParameterModel(parameterName);
+ if (supportsInformals == null && mixinModel.getSupportsInformalParameters())
+ supportsInformals = mixinId;
+ }
+
+ // The component comes last and overwrites simple names from the others.
- if (pmodel != null)
- return createBinder(null, parameterName, pmodel.getDefaultBindingPrefix(), creator);
+ updateParameterNameToQualified(null, componentModel);
- String informalMixinId = null;
+ return supportsInformals;
+ }
- for (Map.Entry<String, ComponentModel> me : mixinIdToComponentModel.entrySet())
+ private void updateParameterNameToQualified(String mixinId, ComponentModel model)
+ {
+ for (String parameterName : model.getParameterNames())
{
- String mixinId = me.getKey();
- ComponentModel model = me.getValue();
+ String defaultBindingPrefix = model.getParameterModel(parameterName).getDefaultBindingPrefix();
- if (informalMixinId == null && model.getSupportsInformalParameters())
- informalMixinId = mixinId;
+ ParameterBinderImpl binder = new ParameterBinderImpl(mixinId, parameterName, defaultBindingPrefix);
- pmodel = model.getParameterModel(parameterName);
+ parameterNameToBinder.put(parameterName,
+ binder);
- if (pmodel != null)
- return createBinder(mixinId, parameterName, pmodel.getDefaultBindingPrefix(), creator);
+ if (mixinId != null)
+ parameterNameToBinder.put(mixinId + "." + parameterName, binder);
}
+ }
- // OK, it doesn't match any formal parameter of the component or any mixin.
+ private void addMixin(String className)
+ {
+ ComponentModel model = getModel(className);
- // If neither the component nor any of its mixins supports informal parameters,
- // then return null to ignore the parameter.
+ String mixinId = InternalUtils.lastTerm(className);
- if (informalMixinId == null && !componentModel.getSupportsInformalParameters()) return null;
+ if (mixinIdToComponentModel.containsKey(mixinId))
+ throw new TapestryException(
+ String.format("Mixins applied to a component must be unique. Mixin '%s' has already been applied.",
+ mixinId),
+ location, 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);
+ mixinIdToComponentModel.put(mixinId, model);
}
- private ParameterBinder createQualifiedParameterBinder(String mixinId, String parameterName,
- String defaultBindingPrefix,
- BindingCreator creator)
+ private ComponentModel getModel(String className)
{
- ComponentModel mixinModel = mixinIdToComponentModel.get(mixinId);
+ return instantiatorSource.getInstantiator(className).getModel();
+ }
- if (mixinModel == null)
+ public ParameterBinder createParameterBinder(String parameterName)
+ {
+ int dotx = parameterName.indexOf('.');
+ if (dotx >= 0)
{
- String message = String.format(
- "Parameter '%s.%s' does not match any defined mixins for this component. Available mixins: %s.",
- mixinId, parameterName,
- InternalUtils.sortedKeys(mixinIdToComponentModel));
+ String mixinId = parameterName.substring(0, dotx);
+ if (!mixinIdToComponentModel.containsKey(mixinId))
+ {
+ String message = String.format("Mixin id for parameter '%s' not found. Attached mixins: %s.",
+ parameterName,
+ InternalUtils.joinSorted(mixinIdToComponentModel.keySet()));
- throw new TapestryException(message, location, null);
+ throw new TapestryException(message, location, null);
+ }
}
+ else
+ {
+ // Unqualified parameter name. May be a reference not to a parameter of this component, but a published
+ // parameter of a component embedded in this component. The ComponentAssembler for this component
+ // will know.
- return createBinder(mixinId, mixinModel, parameterName, defaultBindingPrefix, creator);
- }
+ ComponentAssembler assembler = assemblerSource.getAssembler(componentModel.getComponentClassName(), locale);
- private ParameterBinder createBinder(String mixinId,
- ComponentModel model,
- String parameterName,
- String defaultBindingPrefix,
- BindingCreator creator)
- {
- ParameterModel pmodel = model.getParameterModel(parameterName);
+ ParameterBinder binder = assembler.getBinder(parameterName);
- // Ignore informal parameters for mixins that don't support them.
+ if (binder != null) return binder;
+ }
- if (pmodel == null && !model.getSupportsInformalParameters())
- return null;
+ final ParameterBinder binder = parameterNameToBinder.get(parameterName);
- final String bindingPrefix = pmodel == null ? defaultBindingPrefix : pmodel.getDefaultBindingPrefix();
+ if (binder != null)
+ return binder;
- return createBinder(mixinId, parameterName, bindingPrefix, creator);
- }
+ // Informal parameter: Is there a mixin for that?
- 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);
- }
- };
+ if (informalParametersMixinId != null)
+ return new ParameterBinderImpl(informalParametersMixinId, parameterName, null);
+
+ if (componentModel.getSupportsInformalParameters())
+ return new ParameterBinderImpl(null, parameterName, null);
+
+ // Otherwise, informal parameter and not supported by the component or any mixin.
+
+ return null;
}
public boolean isBound(String parameterName)
@@ -233,4 +228,25 @@
bound.put(parameterName, true);
}
+
+ public void addMixinsToElement(ComponentPageElement newElement)
+ {
+ for (Map.Entry<String, ComponentModel> entry : mixinIdToComponentModel.entrySet())
+ {
+ String mixinId = entry.getKey();
+ ComponentModel model = entry.getValue();
+
+ // TODO: Change mixinIdTo... to be to Instantiator instead, so we don't have to
+ // keep asking the IS for them.
+
+ Instantiator instantiator = instantiatorSource.getInstantiator(model.getComponentClassName());
+
+ newElement.addMixin(mixinId, instantiator);
+ }
+ }
+
+ public Location getLocation()
+ {
+ return location;
+ }
}
Modified: 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=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageAssembly.java Sun Feb 15 04:44:12 2009
@@ -17,7 +17,9 @@
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.Location;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.TapestryException;
import org.apache.tapestry5.ioc.util.Stack;
import org.apache.tapestry5.runtime.RenderCommand;
@@ -30,17 +32,19 @@
*/
class PageAssembly
{
- public final Page page;
+ final Page page;
- public final Stack<ComponentPageElement> activeElement = CollectionFactory.newStack();
+ final Stack<ComponentPageElement> activeElement = CollectionFactory.newStack();
- public final Stack<BodyPageElement> bodyElement = CollectionFactory.newStack();
+ final Stack<BodyPageElement> bodyElement = CollectionFactory.newStack();
- public final Stack<ComponentPageElement> createdElement = CollectionFactory.newStack();
+ final Stack<ComponentPageElement> createdElement = CollectionFactory.newStack();
- public final Stack<EmbeddedComponentAssembler> embeddedAssembler = CollectionFactory.newStack();
+ final Stack<ComponentName> componentName = CollectionFactory.newStack();
- public final List<PageAssemblyAction> deferred = CollectionFactory.newList();
+ final Stack<EmbeddedComponentAssembler> embeddedAssembler = CollectionFactory.newStack();
+
+ final List<PageAssemblyAction> deferred = CollectionFactory.newList();
private final List<RenderCommand> composableRenderCommands = CollectionFactory.newList();
@@ -57,7 +61,7 @@
*
* @param command
*/
- public void addRenderCommand(RenderCommand command)
+ void addRenderCommand(RenderCommand command)
{
flushComposableRenderCommands();
@@ -70,7 +74,7 @@
*
* @param command
*/
- public void addComposableRenderCommand(RenderCommand command)
+ void addComposableRenderCommand(RenderCommand command)
{
composableRenderCommands.add(command);
}
@@ -79,7 +83,7 @@
* 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()
+ void flushComposableRenderCommands()
{
int count = composableRenderCommands.size();
@@ -102,7 +106,7 @@
composableRenderCommands.clear();
}
- public boolean checkAndSetFlag(String flagName)
+ boolean checkAndSetFlag(String flagName)
{
boolean result = flags.contains(flagName);
@@ -111,6 +115,23 @@
return result;
}
+
+ void checkForRecursion(String componentClassName, Location location)
+ {
+ for (Object o : activeElement.getSnapshot())
+ {
+ ComponentPageElement e = (ComponentPageElement) o;
+
+ if (e.getComponentResources().getComponentModel().getComponentClassName().equals(componentClassName))
+ {
+ String message = String.format(
+ "The template for component %s is recursive (contains another direct or indirect reference to component %<s). This is not supported (components may not contain themselves).",
+ componentClassName);
+
+ throw new TapestryException(message, location, null);
+ }
+ }
+ }
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java?rev=744608&r1=744607&r2=744608&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java Sun Feb 15 04:44:12 2009
@@ -20,7 +20,6 @@
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.internal.InternalComponentResources;
import org.apache.tapestry5.internal.InternalConstants;
-import org.apache.tapestry5.internal.TapestryInternalUtils;
import org.apache.tapestry5.internal.bindings.LiteralBinding;
import org.apache.tapestry5.internal.parser.*;
import org.apache.tapestry5.internal.services.*;
@@ -36,15 +35,25 @@
import org.apache.tapestry5.services.ComponentClassResolver;
import org.apache.tapestry5.services.InvalidationListener;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* There's still a lot of room to beef up {@link org.apache.tapestry5.internal.pageload.ComponentAssembler} and {@link
* org.apache.tapestry5.internal.pageload.EmbeddedComponentAssembler} to perform more static analysis.
+ * <p/>
+ * Loading a page involves a recurive process of creating {@link org.apache.tapestry5.internal.pageload.ComponentAssembler}s:
+ * for the root component, then down the tree for each embedded component. A ComponentAssembler is largely a collection
+ * of {@link org.apache.tapestry5.internal.pageload.PageAssemblyAction}s. Once created, a ComponentAssembler can quickly
+ * assemble any number of component instances. All of the expensive logic, such as fitting template tokens together and
+ * matching parameters to bindings, is done as part of the one-time construction of the ComponentAssembler. The end
+ * result removes a huge amount of computational redundancy that was present in Tapestry 5.0, but to understand this,
+ * you need to split your mind into two phases: construction (of the ComponentAssemblers) and assembly. It's twisted ...
+ * and perhaps a bit functional and Monadic.
+ * <p/>
+ * And truly, <em>This is the Tapestry Heart, This is the Tapestry Soul...</em>
*/
-public class PageLoaderImpl implements PageLoader, InvalidationListener
+public class PageLoaderImpl implements PageLoader, InvalidationListener, ComponentAssemblerSource
{
private static final class Key
{
@@ -181,7 +190,7 @@
return page;
}
- private ComponentAssembler getAssembler(String className, Locale locale)
+ public ComponentAssembler getAssembler(String className, Locale locale)
{
Key key = new Key(className, locale);
@@ -206,7 +215,8 @@
ComponentPageElementResources resources = resourcesSource.get(locale);
- ComponentAssembler assembler = new ComponentAssemblerImpl(instantiator, resources);
+ ComponentAssembler assembler = new ComponentAssemblerImpl(this, instantiatorSource, componentClassResolver,
+ instantiator, resources, locale);
// "Program" the assembler by adding actions to it. The actions execute every time a new page instance
// is needed.
@@ -224,40 +234,9 @@
{
assembler.validateEmbeddedIds(template);
- // TODO: Optimize for the case of the empty template.
-
- addImplementationMixins(assembler);
-
processTemplate(assembler, template);
}
- /**
- * Add any mixins defined for the component (implementation mixins, rather than instance mixins).
- */
-
- private void addImplementationMixins(ComponentAssembler assembler)
- {
- final List<String> mixinClassNames = assembler.getModel().getMixinClassNames();
-
- if (mixinClassNames.isEmpty()) return;
-
- assembler.add(new PageAssemblyAction()
- {
- public void execute(PageAssembly pageAssembly)
- {
- ComponentPageElement element = pageAssembly.activeElement.peek();
-
- for (String className : mixinClassNames)
- {
- Instantiator mixinInstantiator = instantiatorSource.getInstantiator(className);
-
- element.addMixin(InternalUtils.lastTerm(className), mixinInstantiator);
-
- }
- }
- });
- }
-
private void processTemplate(ComponentAssembler assembler, ComponentTemplate template)
{
if (template.isMissing())
@@ -429,7 +408,7 @@
EmbeddedComponentAssembler embeddedAssembler = pageAssembly.embeddedAssembler.peek();
- ParameterBinder binder = embeddedAssembler.createBinder(parameterName, binding);
+ ParameterBinder binder = embeddedAssembler.createParameterBinder(parameterName);
if (binder == null)
{
@@ -441,7 +420,7 @@
throw new TapestryException(message, token.getLocation(), null);
}
- binder.bind(pageAssembly.activeElement.peek(), element);
+ binder.bind(pageAssembly.createdElement.peek(), binding);
pageAssembly.bodyElement.push(block);
}
@@ -454,15 +433,12 @@
{
final BlockToken token = stream.next(BlockToken.class);
- final String blockId = token.getId();
-
- // TODO: The description string should be calculatable statically, we just need
- // to keep yet another stack (of complete component ids).
-
assembler.add(new PageAssemblyAction()
{
public void execute(PageAssembly pageAssembly)
{
+ String blockId = token.getId();
+
ComponentPageElement element = pageAssembly.activeElement.peek();
String description = blockId == null
@@ -552,7 +528,7 @@
AttributeToken token)
{
addParameterBindingAction(assembler, embeddedAssembler, token.getName(), token.getValue(),
- BindingConstants.LITERAL);
+ BindingConstants.LITERAL, token.getLocation());
}
private void element(ComponentAssembler assembler, TokenStream stream)
@@ -653,19 +629,16 @@
// OK, now we can record an action to get it instantiated.
- EmbeddedComponentAssembler embeddedAssembler = new EmbeddedComponentAssemblerImpl(instantiatorSource,
- elementFactory,
- componentClassName,
- token.getLocation());
-
- addActionForEmbeddedComponent(assembler, embeddedAssembler, embeddedId, elementName, componentClassName,
- token.getLocation());
+ EmbeddedComponentAssembler embeddedAssembler =
+ assembler.createEmbeddedAssembler(embeddedId,
+ componentClassName,
+ embeddedModel,
+ token.getMixins(),
+ token.getLocation());
+ addActionForEmbeddedComponent(assembler, embeddedAssembler, embeddedId, elementName, componentClassName);
- addMixinActions(assembler, embeddedAssembler, embeddedModel, token.getMixins());
-
- bindParametersFromEmbeddedModel(assembler, embeddedAssembler, embeddedModel);
-
+ addParameterBindingActions(assembler, embeddedAssembler, embeddedModel);
if (embeddedModel != null && embeddedModel.getInheritInformalParameters())
{
@@ -715,25 +688,31 @@
}
}
- private void bindParametersFromEmbeddedModel(ComponentAssembler assembler,
- EmbeddedComponentAssembler embeddedAssembler,
- EmbeddedComponentModel embeddedModel)
+ private void addParameterBindingActions(ComponentAssembler assembler,
+ EmbeddedComponentAssembler embeddedAssembler,
+ EmbeddedComponentModel embeddedModel)
{
if (embeddedModel == null) return;
- for (String name : embeddedModel.getParameterNames())
+ for (String parameterName : embeddedModel.getParameterNames())
{
- String parameterValue = embeddedModel.getParameterValue(name);
+ String parameterValue = embeddedModel.getParameterValue(parameterName);
- addParameterBindingAction(assembler, embeddedAssembler, name, parameterValue, BindingConstants.PROP);
+ addParameterBindingAction(assembler,
+ embeddedAssembler,
+ parameterName,
+ parameterValue,
+ BindingConstants.PROP,
+ embeddedModel.getLocation());
}
}
private void addParameterBindingAction(ComponentAssembler assembler,
- EmbeddedComponentAssembler embeddedAssembler,
- String parameterName,
- String parameterValue,
- String defaultBindingPrefix)
+ final EmbeddedComponentAssembler embeddedAssembler,
+ final String parameterName,
+ final String parameterValue,
+ final String metaDefaultBindingPrefix,
+ final Location location)
{
if (embeddedAssembler.isBound(parameterName)) return;
@@ -741,29 +720,45 @@
if (parameterValue.startsWith(InternalConstants.INHERIT_BINDING_PREFIX))
{
-
String containerParameterName = parameterValue.substring(InternalConstants.INHERIT_BINDING_PREFIX.length());
- addInhertedBindingAction(assembler, parameterName, containerParameterName);
+ addInheritedBindingAction(assembler, parameterName, containerParameterName);
return;
}
- final ParameterBinder binder = embeddedAssembler.createBinder(parameterName, parameterValue,
- defaultBindingPrefix);
-
- // Null meaning an informal parameter and the component (and mixins) doesn't support informals.
-
- if (binder != null)
+ assembler.add(new PageAssemblyAction()
{
- assembler.add(new PageAssemblyAction()
+ public void execute(PageAssembly pageAssembly)
{
- public void execute(PageAssembly pageAssembly)
+ // Because of published parameters, we have to wait until page assembly time to throw out
+ // informal parameters bound to components that don't support informal parameters ...
+ // otherwise we'd throw out (sometimes!) published parameters.
+
+ final ParameterBinder binder = embeddedAssembler.createParameterBinder(parameterName);
+
+ // Null meaning an informal parameter and the component (and mixins) doesn't support informals.
+
+ if (binder != null)
{
- binder.bind(pageAssembly.activeElement.peek(), pageAssembly.createdElement.peek());
+ final String defaultBindingPrefix = binder.getDefaultBindingPrefix(metaDefaultBindingPrefix);
+
+ InternalComponentResources containerResources = pageAssembly.activeElement.peek().getComponentResources();
+
+ ComponentPageElement embeddedElement = pageAssembly.createdElement.peek();
+ InternalComponentResources embeddedResources = embeddedElement.getComponentResources();
+
+ Binding binding = elementFactory.newBinding(parameterName,
+ containerResources,
+ embeddedResources,
+ defaultBindingPrefix,
+ parameterValue,
+ location);
+
+ binder.bind(embeddedElement, binding);
}
- });
- }
+ }
+ });
}
/**
@@ -774,9 +769,9 @@
* @param parameterName
* @param containerParameterName
*/
- private void addInhertedBindingAction(ComponentAssembler assembler,
- final String parameterName,
- final String containerParameterName)
+ private void addInheritedBindingAction(ComponentAssembler assembler,
+ final String parameterName,
+ final String containerParameterName)
{
assembler.add(new PageAssemblyAction()
{
@@ -805,13 +800,13 @@
String containerParameterName)
{
// TODO: This assumes that the two parameters are both on the core component and not on
- // a mixin.
+ // a mixin. I think this could be improved with more static analysis.
Binding containerBinding = container.getBinding(containerParameterName);
if (containerBinding == null) return;
- String description = String.format("InheritedBinding[parameter %s %s(inherited from %s of %s)]",
+ String description = String.format("InheritedBinding[parameter %s %s (inherited from %s of %s)]",
parameterName,
embedded.getCompleteId(),
containerParameterName,
@@ -821,84 +816,23 @@
// to the location of the inherited binding, rather than the container component's
// binding.
- Binding inherited = new InheritedBinding(description, containerBinding, embedded.getLocation());
+ // Binding inherited = new InheritedBinding(description, containerBinding, embedded.getLocation());
- embedded.bindParameter(parameterName, inherited);
- }
-
- private ComponentModel getModel(String componentClassName)
- {
- return instantiatorSource.getInstantiator(componentClassName).getModel();
- }
-
- private void addMixinActions(ComponentAssembler assembler,
- EmbeddedComponentAssembler embeddedAssembler, EmbeddedComponentModel model,
- String mixins
- )
- {
- if (model != null)
- {
- addMixinActionsFromEmbeddedModel(assembler, embeddedAssembler, model);
- }
-
- List<String> classNames = CollectionFactory.newList();
-
- for (String typeName : TapestryInternalUtils.splitAtCommas(mixins))
- {
- classNames.add(componentClassResolver.resolveMixinTypeToClassName(typeName));
- }
-
- addMixinActionsForClassNames(assembler, embeddedAssembler, classNames);
- }
-
- private void addMixinActionsFromEmbeddedModel(ComponentAssembler assembler,
- EmbeddedComponentAssembler embeddedAssembler,
- EmbeddedComponentModel model
- )
- {
- addMixinActionsForClassNames(assembler, embeddedAssembler, model.getMixinClassNames());
- }
-
- private void addMixinActionsForClassNames(ComponentAssembler assembler,
- EmbeddedComponentAssembler embeddedAssembler,
- final List<String> classNames
- )
- {
- for (String className : classNames)
- {
- embeddedAssembler.addInstanceMixin(getModel(className));
- }
-
- if (!classNames.isEmpty())
- {
- assembler.add(new PageAssemblyAction()
- {
- public void execute(PageAssembly pageAssembly)
- {
- ComponentPageElement embedded = pageAssembly.createdElement.peek();
-
- for (String className : classNames)
- {
- Instantiator instantiator = instantiatorSource.getInstantiator(className);
-
- embedded.addMixin(InternalUtils.lastTerm(className), instantiator);
- }
- }
- });
- }
+ embedded.bindParameter(parameterName, containerBinding);
}
private void addActionForEmbeddedComponent(ComponentAssembler assembler,
final EmbeddedComponentAssembler embeddedAssembler,
final String embeddedId,
final String elementName,
- final String componentClassName,
- final Location location)
+ final String componentClassName)
{
assembler.add(new PageAssemblyAction()
{
public void execute(PageAssembly pageAssembly)
{
+ pageAssembly.checkForRecursion(componentClassName, embeddedAssembler.getLocation());
+
pageAssembly.flushComposableRenderCommands();
Locale locale = pageAssembly.page.getLocale();
@@ -907,7 +841,8 @@
// Remeber: this pushes onto to the createdElement stack, but does not pop it.
- assemblerForSubcomponent.assembleEmbeddedComponent(pageAssembly, embeddedId, elementName, location);
+ assemblerForSubcomponent.assembleEmbeddedComponent(pageAssembly, embeddedAssembler, embeddedId,
+ elementName, embeddedAssembler.getLocation());
// ... which is why we can find it via peek() here. And it's our responsibility
// to clean it up.
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ParameterBinder.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ParameterBinder.java?rev=744608&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ParameterBinder.java (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/ParameterBinder.java Sun Feb 15 04:44:12 2009
@@ -0,0 +1,47 @@
+// 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.internal.structure.ComponentPageElement;
+
+/**
+ * Encapsulates the result of a parameter lookup, i.e., the conversion from qualified or unqualified parameter name to
+ * mixin id (or null) and parameter name, as well as the default binding prefix for the parameter.
+ *
+ * @see org.apache.tapestry5.internal.pageload.EmbeddedComponentAssembler#createParameterBinder(String)
+ */
+interface ParameterBinder
+{
+ /**
+ * Bindings the parameter of the element. The name (and optionally mixinid) of the parameter is determined when
+ * the ParameterBinder is created.
+ *
+ * @param element page element to bind
+ * @param binding binding for the parameter
+ */
+ void bind(ComponentPageElement element, Binding binding);
+
+ /**
+ * Returns the correct default binding prefix to use for this parameter, which is either the {@linkplain
+ * org.apache.tapestry5.model.ParameterModel#getDefaultBindingPrefix() default binding prefix configured for the
+ * parameter}, or the meta-default (when binding an informal parameter). A specific binding of a parameter may
+ * always override the default binding prefix, however it is calculated.
+ *
+ * @param metaDefault
+ * @return binding prefix
+ */
+ String getDefaultBindingPrefix(String metaDefault);
+}