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/04/18 00:22:42 UTC
svn commit: r766168 - in /tapestry/tapestry5/trunk/tapestry-core/src:
main/java/org/apache/tapestry5/internal/services/
test/java/org/apache/tapestry5/internal/services/
test/resources/org/apache/tapestry5/internal/services/
Author: hlship
Date: Fri Apr 17 22:22:41 2009
New Revision: 766168
URL: http://svn.apache.org/viewvc?rev=766168&view=rev
Log:
TAP5-571: Misplaced <t:parameter> results in an inscrutable exception
Added:
tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/misplaced_parameter.tml
Modified:
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java?rev=766168&r1=766167&r2=766168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/StaxTemplateParser.java Fri Apr 17 22:22:41 2009
@@ -314,50 +314,7 @@
/**
* Processes an element through to its matching end tag.
- */
- void element(TemplateParserState initialState) throws XMLStreamException
- {
- TemplateParserState state = setupForElement(initialState);
-
- if (!processStartElement(state)) return;
-
- // Now start working through the body of the element, recursively.
-
- while (active)
- {
- switch (reader.next())
- {
- case START_ELEMENT:
-
- // The recursive part: when we see a new element start.
-
- element(state);
- break;
-
- case END_ELEMENT:
-
- // At the end of an element, we're done and can return.
- // This is the matching end element for the start element
- // that invoked this method.
-
- endElement(state);
-
- return;
-
- default:
- textContent(state);
- }
- }
- }
-
- private TemplateParserState setupForElement(TemplateParserState initialState)
- {
- processTextBuffer(initialState);
-
- return checkForXMLSpaceAttribute(initialState);
- }
-
- /**
+ * <p/>
* An element can be:
* <p/>
* a Tapestry component via <t:type>
@@ -379,12 +336,11 @@
* The body <t:body>
* <p/>
* An ordinary element
- *
- * @return true if processing of the elements body should continue normally, or false if the elements body (and end
- * tag) have already been consumed
*/
- private boolean processStartElement(TemplateParserState state) throws XMLStreamException
+ void element(TemplateParserState initialState) throws XMLStreamException
{
+ TemplateParserState state = setupForElement(initialState);
+
String uri = reader.getNamespaceURI();
String name = reader.getLocalName();
@@ -395,21 +351,21 @@
{
removeContent();
- return false;
+ return;
}
if (name.equalsIgnoreCase("content"))
{
limitContent(state);
- return false;
+ return;
}
if (name.equalsIgnoreCase("extension-point"))
{
extensionPoint(state);
- return false;
+ return;
}
if (name.equalsIgnoreCase("replace"))
@@ -427,7 +383,7 @@
if (name.equalsIgnoreCase("body"))
{
body();
- return false;
+ return;
}
if (name.equalsIgnoreCase("container"))
@@ -438,43 +394,82 @@
if (name.equalsIgnoreCase("block"))
{
block(state);
- return false;
+ return;
}
if (name.equalsIgnoreCase("parameter"))
{
- classicParameter();
+ classicParameter(state);
- // Default handling for the body of the parameter is acceptible.
- return true;
+ return;
}
- possibleTapestryComponent(null, reader.getLocalName().replace('.', '/'));
+ possibleTapestryComponent(state, null, reader.getLocalName().replace('.', '/'));
- return true;
+ return;
}
if (uri != null && uri.startsWith(LIB_NAMESPACE_URI_PREFIX))
{
- libraryNamespaceComponent();
+ libraryNamespaceComponent(state);
- return true;
+ return;
}
if (TAPESTRY_PARAMETERS_URI.equals(uri))
{
- parameterElement();
+ parameterElement(state);
- return true;
+ return;
}
// Just an ordinary element ... unless it has t:id or t:type
- possibleTapestryComponent(reader.getLocalName(), null);
+ possibleTapestryComponent(state, reader.getLocalName(), null);
+ }
+
+ /**
+ * Processes a body of an element including text and (recursively) nested elements. Adds an {@link
+ * org.apache.tapestry5.internal.parser.TokenType#END_ELEMENT} token before returning.
+ *
+ * @param state
+ * @throws XMLStreamException
+ */
+ private void processBody(TemplateParserState state)
+ throws XMLStreamException
+ {
+ while (active)
+ {
+ switch (reader.next())
+ {
+ case START_ELEMENT:
+
+ // The recursive part: when we see a new element start.
+
+ element(state);
+ break;
+
+ case END_ELEMENT:
+
+ // At the end of an element, we're done and can return.
+ // This is the matching end element for the start element
+ // that invoked this method.
+
+ endElement(state);
+
+ return;
+
+ default:
+ textContent(state);
+ }
+ }
+ }
- // Let element() take it from here (body plus end element token).
+ private TemplateParserState setupForElement(TemplateParserState initialState)
+ {
+ processTextBuffer(initialState);
- return true;
+ return checkForXMLSpaceAttribute(initialState);
}
/**
@@ -492,7 +487,7 @@
tokenAccumulator.add(new ExtensionPointToken(id, getLocation()));
- addContentToOverride(state, id);
+ addContentToOverride(state.insideComponent(false), id);
}
private String getRequiredIdAttribute()
@@ -561,7 +556,7 @@
"The <content> element may not be nested within another <content> element.");
- TemplateParserState newState = state.collectingContent();
+ TemplateParserState newState = state.collectingContent().insideComponent(false);
// Clear out any tokens that precede the <t:content> element
@@ -637,7 +632,7 @@
/**
* Added in release 5.1.
*/
- private void libraryNamespaceComponent()
+ private void libraryNamespaceComponent(TemplateParserState state) throws XMLStreamException
{
String uri = reader.getNamespaceURI();
@@ -648,14 +643,15 @@
if (!LIBRARY_PATH_PATTERN.matcher(path).matches())
throw new RuntimeException(ServicesMessages.invalidPathForLibraryNamespace(uri));
- possibleTapestryComponent(null, path + "/" + reader.getLocalName());
+ possibleTapestryComponent(state, null, path + "/" + reader.getLocalName());
}
/**
* @param elementName
* @param identifiedType the type of the element, usually null, but may be the component type derived from element
*/
- private void possibleTapestryComponent(String elementName, String identifiedType)
+ private void possibleTapestryComponent(TemplateParserState state, String elementName, String identifiedType)
+ throws XMLStreamException
{
String id = null;
String type = identifiedType;
@@ -736,6 +732,8 @@
if (id != null)
componentIds.put(id, location);
+
+ processBody(state.insideComponent(isComponent));
}
private void addDefineNamespaceTokens()
@@ -789,26 +787,40 @@
* Handler for Tapestry 5.0's "classic" <t:parameter> element. This turns into a {@link
* org.apache.tapestry5.internal.parser.ParameterToken} and the body and end element are provided normally.
*/
- private void classicParameter()
+ private void classicParameter(TemplateParserState state) throws XMLStreamException
{
String parameterName = getSingleParameter("name");
if (InternalUtils.isBlank(parameterName))
throw new TapestryException(ServicesMessages.parameterElementNameRequired(), getLocation(), null);
+ ensureParameterWithinComponent(state);
+
tokenAccumulator.add(new ParameterToken(parameterName, getLocation()));
+
+ processBody(state.insideComponent(false));
+ }
+
+ private void ensureParameterWithinComponent(TemplateParserState state)
+ {
+ if (!state.isInsideComponent())
+ throw new RuntimeException("Block parameters are only allowed directly within component elements.");
}
/**
* Tapestry 5.1 uses a special namespace (usually mapped to "p:") and the name becomes the parameter element.
*/
- private void parameterElement()
+ private void parameterElement(TemplateParserState state) throws XMLStreamException
{
+ ensureParameterWithinComponent(state);
+
if (reader.getAttributeCount() > 0)
throw new TapestryException(ServicesMessages.parameterElementDoesNotAllowAttributes(), getLocation(),
null);
tokenAccumulator.add(new ParameterToken(reader.getLocalName(), getLocation()));
+
+ processBody(state.insideComponent(false));
}
@@ -874,23 +886,7 @@
tokenAccumulator.add(new BlockToken(blockId, getLocation()));
- while (active)
- {
- switch (reader.next())
- {
- case START_ELEMENT:
- element(state);
- break;
-
- case END_ELEMENT:
- endElement(state);
- return;
-
- default:
- textContent(state);
- }
- }
-
+ processBody(state.insideComponent(false));
}
private String getSingleParameter(String attributeName)
Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java?rev=766168&r1=766167&r2=766168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/TemplateParserState.java Fri Apr 17 22:22:41 2009
@@ -26,26 +26,40 @@
private final boolean collectingContent;
+ private final boolean insideComponent;
+
TemplateParserState()
{
compressWhitespace = false;
collectingContent = false;
+ insideComponent = false;
}
- private TemplateParserState(boolean compressWhitespace, boolean collectingContent)
+ private TemplateParserState(boolean compressWhitespace, boolean collectingContent, boolean insideComponent)
{
this.compressWhitespace = compressWhitespace;
this.collectingContent = collectingContent;
+ this.insideComponent = insideComponent;
}
TemplateParserState compressWhitespace(boolean flag)
{
- return new TemplateParserState(flag, collectingContent);
+ return flag == compressWhitespace ? this : new TemplateParserState(flag, collectingContent, insideComponent);
}
TemplateParserState collectingContent()
{
- return new TemplateParserState(compressWhitespace, true);
+ return collectingContent ? this : new TemplateParserState(compressWhitespace, true, insideComponent);
+ }
+
+ TemplateParserState insideComponent(boolean flag)
+ {
+ return flag == insideComponent ? this : new TemplateParserState(compressWhitespace, collectingContent, flag);
+ }
+
+ boolean isInsideComponent()
+ {
+ return insideComponent;
}
boolean isCompressWhitespace()
@@ -64,7 +78,7 @@
@Override
public String toString()
{
- return String.format("TemplateParserState[compressWhitespace=%s, collectingContent=%s]", compressWhitespace,
- collectingContent);
+ return String.format("TemplateParserState[compressWhitespace=%s, collectingContent=%s, insideComponent=%s]",
+ compressWhitespace, collectingContent, insideComponent);
}
}
Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java?rev=766168&r1=766167&r2=766168&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/TemplateParserImplTest.java Fri Apr 17 22:22:41 2009
@@ -694,7 +694,11 @@
{ "missing_id_in_replace_element.tml", "The <replace> element must have an id attribute.", 3 },
- { "extension_point_must_have_id.tml", "The <extension-point> element must have an id attribute.", 3 }
+ { "extension_point_must_have_id.tml", "The <extension-point> element must have an id attribute.", 3 },
+
+ { "misplaced_parameter.tml", "Block parameters are only allowed directly within component elements.",
+ 5 },
+
};
}
Added: tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/misplaced_parameter.tml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/misplaced_parameter.tml?rev=766168&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/misplaced_parameter.tml (added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/resources/org/apache/tapestry5/internal/services/misplaced_parameter.tml Fri Apr 17 22:22:41 2009
@@ -0,0 +1,9 @@
+<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"
+ xmlns:p="tapestry:parameter">
+
+ <not-a-component>
+ <p:foo/>
+ </not-a-component>
+
+</t:container>
+