You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by jd...@apache.org on 2010/12/04 16:13:39 UTC

svn commit: r1042202 - in /wicket/trunk/wicket/src: main/java/org/apache/wicket/ main/java/org/apache/wicket/markup/ main/java/org/apache/wicket/markup/html/ test/java/org/apache/wicket/markup/parser/filter/

Author: jdonnerstag
Date: Sat Dec  4 15:13:38 2010
New Revision: 1042202

URL: http://svn.apache.org/viewvc?rev=1042202&view=rev
Log:
a bit of cleanup on header containers

Added:
    wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_20.html
    wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.html
    wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.java
Modified:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/TagUtils.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/ContainerWithAssociatedMarkupHelper.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/HeaderPartContainer.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainer.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java
    wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionTest.java

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Component.java Sat Dec  4 15:13:38 2010
@@ -4144,7 +4144,7 @@ public abstract class Component
 	 * @param parent
 	 *            The parent container
 	 */
-	final void setParent(final MarkupContainer parent)
+	public final void setParent(final MarkupContainer parent)
 	{
 		if (this.parent != null && log.isDebugEnabled())
 		{

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/TagUtils.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/TagUtils.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/TagUtils.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/TagUtils.java Sat Dec  4 15:13:38 2010
@@ -42,13 +42,21 @@ public class TagUtils
 	}
 
 	/**
-	 * @return True, if tag name equals '<head ...>'
 	 * 
-	 * @param tag
+	 * @param elem
+	 * @return True, if tag name equals '<head ...>'
 	 */
-	public static final boolean isHeadTag(final ComponentTag tag)
+	public static final boolean isHeadTag(final MarkupElement elem)
 	{
-		return ("head".equalsIgnoreCase(tag.getName()) && (tag.getNamespace() == null));
+		if (elem instanceof ComponentTag)
+		{
+			ComponentTag tag = (ComponentTag)elem;
+			if ("head".equalsIgnoreCase(tag.getName()) && (tag.getNamespace() == null))
+			{
+				return true;
+			}
+		}
+		return false;
 	}
 
 	/**
@@ -79,4 +87,22 @@ public class TagUtils
 		}
 		return false;
 	}
+
+	/**
+	 * 
+	 * @param elem
+	 * @return True if the current markup element is a <wicket:head> tag
+	 */
+	public static final boolean isWicketHeadTag(final MarkupElement elem)
+	{
+		if (elem instanceof WicketTag)
+		{
+			WicketTag wtag = (WicketTag)elem;
+			if (wtag.isHeadTag())
+			{
+				return true;
+			}
+		}
+		return false;
+	}
 }
\ No newline at end of file

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/ContainerWithAssociatedMarkupHelper.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/ContainerWithAssociatedMarkupHelper.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/ContainerWithAssociatedMarkupHelper.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/ContainerWithAssociatedMarkupHelper.java Sat Dec  4 15:13:38 2010
@@ -16,17 +16,17 @@
  */
 package org.apache.wicket.markup.html;
 
+import org.apache.wicket.Component;
 import org.apache.wicket.IClusterable;
 import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.IMarkupFragment;
 import org.apache.wicket.markup.MarkupElement;
 import org.apache.wicket.markup.MarkupException;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.TagUtils;
 import org.apache.wicket.markup.WicketTag;
 import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
-import org.apache.wicket.request.Response;
-import org.apache.wicket.response.NullResponse;
 import org.apache.wicket.util.lang.Classes;
 
 
@@ -58,7 +58,7 @@ public class ContainerWithAssociatedMark
 	 * <wicket:head> tag.
 	 * <p>
 	 * Whereas 'this' might be a Panel or Border, the HtmlHeaderContainer parameter has been added
-	 * to the Page as a container for all headers any of its components might wish to contribute.
+	 * to the Page as a container for all headers any of its components might wish to contribute to.
 	 * <p>
 	 * The headers contributed are rendered in the standard way.
 	 * 
@@ -79,14 +79,12 @@ public class ContainerWithAssociatedMark
 		noMoreWicketHeadTagsAllowed = false;
 		while (nextHeaderMarkup(markupStream) != -1)
 		{
-			Class<?> markupClass = markupStream.getTag().getMarkupClass();
-			if (markupClass == null)
-			{
-				markupClass = markupStream.getContainerClass();
-			}
+			// found <wicket:head>
+			String headerId = getHeaderId(container, markupStream);
+
 			// Create a HeaderPartContainer and associate the markup
-			final HeaderPartContainer headerPart = getHeaderPart(markupClass,
-				markupStream.getCurrentIndex());
+			HeaderPartContainer headerPart = getHeaderPart(headerId,
+				markupStream.getMarkupFragment());
 			if (headerPart != null)
 			{
 				// A component's header section must only be added once,
@@ -94,26 +92,10 @@ public class ContainerWithAssociatedMark
 				// to the page or any other container in the hierarchy.
 				if (htmlContainer.okToRenderComponent(headerPart.getScope(), headerPart.getId()))
 				{
-					htmlContainer.autoAdd(headerPart, null);
+					// make sure the Page is accessible
+					headerPart.setParent(htmlContainer);
 					headerPart.render();
 				}
-				else
-				{
-					// TODO Performance: I haven't found a more efficient solution yet.
-					// Already added but all the components in this header part
-					// must be touched (that they are rendered)
-					Response response = container.getRequestCycle().getResponse();
-					try
-					{
-						container.getRequestCycle().setResponse(NullResponse.getInstance());
-						htmlContainer.autoAdd(headerPart, null);
-						headerPart.render();
-					}
-					finally
-					{
-						container.getRequestCycle().setResponse(response);
-					}
-				}
 			}
 
 			// Position the stream after <wicket:head>
@@ -122,51 +104,55 @@ public class ContainerWithAssociatedMark
 	}
 
 	/**
-	 * Gets the header part of the Panel/Border. Returns null if it doesn't have a header tag.
 	 * 
-	 * @param index
-	 *            A unique index
-	 * @param markupClass
-	 *            The java class the wicket:head tag is directly associated with
-	 * @return the header part for this panel/border or null if it doesn't have a wicket:head tag.
+	 * @param container
+	 * @param markupStream
+	 * @return The header id
 	 */
-	private final HeaderPartContainer getHeaderPart(final Class<?> markupClass, final int index)
+	private String getHeaderId(final Component container, final MarkupStream markupStream)
 	{
-		// Gracefully getAssociateMarkupStream. Throws no exception in case
-		// markup is not found
-		final MarkupStream markupStream = container.getAssociatedMarkupStream(false);
+		Class<?> markupClass = markupStream.getTag().getMarkupClass();
+		if (markupClass == null)
+		{
+			markupClass = markupStream.getContainerClass();
+		}
 
-		// Position markup stream at beginning of header tag
-		markupStream.setCurrentIndex(index);
+		// create a unique id for the HtmlHeaderContainer
+		StringBuilder builder = new StringBuilder(100);
+		builder.append("_");
+		builder.append(Classes.simpleName(markupClass));
+		if (container.getVariation() != null)
+		{
+			builder.append(container.getVariation());
+		}
+		builder.append("Header");
+		builder.append(markupStream.getCurrentIndex());
+		return builder.toString();
+	}
 
+	/**
+	 * Gets the header part of the Panel/Border. Returns null if it doesn't have a header tag.
+	 * 
+	 * @param id
+	 * @param markup
+	 * @return the header part for this panel/border or null if it doesn't have a wicket:head tag.
+	 */
+	private final HeaderPartContainer getHeaderPart(final String id, final IMarkupFragment markup)
+	{
 		// Create a HtmlHeaderContainer for the header tag found
-		final MarkupElement element = markupStream.get();
+		final MarkupElement element = markup.get(0);
 		if (element instanceof WicketTag)
 		{
 			final WicketTag wTag = (WicketTag)element;
 			if ((wTag.isHeadTag() == true) && (wTag.getNamespace() != null))
 			{
-				// found <wicket:head>
-				// create a unique id for the HtmlHeaderContainer to be created
-				final String headerId = "_" + Classes.simpleName(markupClass) +
-					(container.getVariation() == null ? "" : container.getVariation()) + "Header" +
-					index;
-
 				// Create the header container and associate the markup with it
-				String scope = wTag.getAttributes().getString(
-					markupStream.getWicketNamespace() + ":scope");
-				HeaderPartContainer headerContainer = new HeaderPartContainer(headerId, container,
-					scope);
-				headerContainer.setMarkup(markupStream.getMarkupFragment());
-				headerContainer.setRenderBodyOnly(true);
-
-				// The container does have a header component
-				return headerContainer;
+				return new HeaderPartContainer(id, container, markup);
 			}
 		}
 
 		throw new WicketRuntimeException("Programming error: expected a WicketTag: " +
-			markupStream.toString());
+			markup.toString());
 	}
 
 	/**
@@ -200,6 +186,7 @@ public class ContainerWithAssociatedMark
 					return associatedMarkupStream.getCurrentIndex();
 				}
 				// wicket:head must be before border, panel or extend
+				// @TODO why is that? Why can't it be anywhere? (except insight wicket:fragment
 				else if (tag.isOpen() &&
 					(tag.isPanelTag() || tag.isBorderTag() || tag.isExtendTag()))
 				{
@@ -210,11 +197,13 @@ public class ContainerWithAssociatedMark
 			{
 				ComponentTag tag = (ComponentTag)elem;
 				// wicket:head must be before </head>
+				// @TODO why??
 				if (tag.isClose() && TagUtils.isHeadTag(tag))
 				{
 					noMoreWicketHeadTagsAllowed = true;
 				}
 				// wicket:head must be before <body>
+				// @TODO why??
 				else if (tag.isOpen() && TagUtils.isBodyTag(tag))
 				{
 					noMoreWicketHeadTagsAllowed = true;

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/HeaderPartContainer.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/HeaderPartContainer.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/HeaderPartContainer.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/HeaderPartContainer.java Sat Dec  4 15:13:38 2010
@@ -19,8 +19,10 @@ package org.apache.wicket.markup.html;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.IMarkupFragment;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.resolver.IComponentResolver;
+import org.apache.wicket.util.lang.Args;
 
 /**
  * For each wicket:head tag a HeaderPartContainer is created and added to the HtmlHeaderContainer
@@ -43,14 +45,35 @@ public final class HeaderPartContainer e
 	 *            The component id
 	 * @param container
 	 *            The Panel (or bordered page) the header part is associated with
-	 * @param scope
-	 *            The scope of the wicket:head tag
+	 * @param markup
 	 */
-	public HeaderPartContainer(final String id, final MarkupContainer container, final String scope)
+	public HeaderPartContainer(final String id, final MarkupContainer container,
+		final IMarkupFragment markup)
 	{
 		super(id);
+
+		Args.notNull(container, "container");
+		Args.notNull(markup, "markup");
+
+		setMarkup(markup);
+
 		this.container = container;
-		this.scope = scope;
+
+		scope = getScopeFromMarkup();
+
+		setRenderBodyOnly(true);
+	}
+
+	/**
+	 * 
+	 * @return get "wicket:scope" attribute from &lt;wicket:head&gt; tag
+	 */
+	private String getScopeFromMarkup()
+	{
+		IMarkupFragment markup = getMarkup();
+		String namespace = markup.getMarkupResourceStream().getWicketNamespace();
+		ComponentTag tag = (ComponentTag)markup.get(0);
+		return tag.getAttributes().getString(namespace + ":scope");
 	}
 
 	/**
@@ -64,7 +87,7 @@ public final class HeaderPartContainer e
 	}
 
 	/**
-	 * @see IComponentResolver#resolve(MarkupContainer, MarkupStream, ComponentTag)
+	 * The tag must be resolved against the panel and not against the page
 	 */
 	public final Component resolve(final MarkupContainer container,
 		final MarkupStream markupStream, final ComponentTag tag)

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainer.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainer.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainer.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainer.java Sat Dec  4 15:13:38 2010
@@ -42,7 +42,7 @@ public class WebMarkupContainer extends 
 	}
 
 	/**
-	 * @see org.apache.wicket.Component#Component(String, IModel)
+	 * @see Component#Component(String, IModel)
 	 */
 	public WebMarkupContainer(final String id, IModel<?> model)
 	{

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java Sat Dec  4 15:13:38 2010
@@ -19,14 +19,15 @@ package org.apache.wicket.markup.html;
 import org.apache.wicket.Component;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.IMarkupFragment;
+import org.apache.wicket.markup.MarkupElement;
+import org.apache.wicket.markup.MarkupException;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.TagUtils;
-import org.apache.wicket.markup.WicketTag;
 import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
 import org.apache.wicket.model.IModel;
 
 /**
- * WebMarkupContainer with it's own markup and possibly <wicket:head> tag.
+ * WebMarkupContainer with it's own markup and possibly &lt;wicket:head&gt; tag.
  * 
  * @author Juergen Donnerstag
  */
@@ -46,57 +47,47 @@ public class WebMarkupContainerWithAssoc
 	}
 
 	/**
-	 * @see org.apache.wicket.Component#Component(String, IModel)
+	 * @see Component#Component(String, IModel)
 	 */
-	public WebMarkupContainerWithAssociatedMarkup(final String id, IModel<?> model)
+	public WebMarkupContainerWithAssociatedMarkup(final String id, final IModel<?> model)
 	{
 		super(id, model);
 	}
 
-	/**
-	 * @see org.apache.wicket.Component#onComponentTag(org.apache.wicket.markup.ComponentTag)
-	 */
 	@Override
-	protected void onComponentTag(ComponentTag tag)
+	protected void onComponentTag(final ComponentTag tag)
 	{
 		// Copy attributes from <wicket:panel> to the "calling" tag
 		IMarkupFragment markup = getMarkup(null);
-		ComponentTag panelTag = (ComponentTag)markup.get(0);
-		for (String key : panelTag.getAttributes().keySet())
+		String namespace = markup.getMarkupResourceStream().getWicketNamespace() + ":";
+
+		MarkupElement elem = markup.get(0);
+		if (elem instanceof ComponentTag)
 		{
-			// exclude "wicket:XX" attributes
-			if (key.startsWith(markup.getMarkupResourceStream().getWicketNamespace() + ":") == false)
+			ComponentTag panelTag = (ComponentTag)elem;
+			for (String key : panelTag.getAttributes().keySet())
 			{
-				tag.append(key, panelTag.getAttribute(key), ", ");
+				// exclude "wicket:XX" attributes
+				if (key.startsWith(namespace) == false)
+				{
+					tag.append(key, panelTag.getAttribute(key), ", ");
+				}
 			}
 		}
+		else
+		{
+			throw new MarkupException(markup.getMarkupResourceStream(),
+				"Expected a Tag but found raw markup: " + elem.toString());
+		}
 
 		super.onComponentTag(tag);
 	}
 
 	/**
-	 * @see org.apache.wicket.Component#renderHead(org.apache.wicket.markup.html.internal.HtmlHeaderContainer)
+	 * Render the header from the associated markup file
 	 */
 	@Override
-	public void renderHead(HtmlHeaderContainer container)
-	{
-		renderHeadFromAssociatedMarkupFile(container);
-		super.renderHead(container);
-	}
-
-	/**
-	 * Called by components like Panel and Border which have associated Markup and which may have a
-	 * &lt;wicket:head&gt; tag.
-	 * <p>
-	 * Whereas 'this' might be a Panel or Border, the HtmlHeaderContainer parameter has been added
-	 * to the Page as a container for all headers any of its components might wish to contribute.
-	 * <p>
-	 * The headers contributed are rendered in the standard way.
-	 * 
-	 * @param container
-	 *            The HtmlHeaderContainer added to the Page
-	 */
-	protected final void renderHeadFromAssociatedMarkupFile(final HtmlHeaderContainer container)
+	public void renderHead(final HtmlHeaderContainer container)
 	{
 		if (markupHelper == null)
 		{
@@ -104,6 +95,8 @@ public class WebMarkupContainerWithAssoc
 		}
 
 		markupHelper.renderHeadFromAssociatedMarkupFile(container);
+
+		super.renderHead(container);
 	}
 
 	/**
@@ -114,28 +107,30 @@ public class WebMarkupContainerWithAssoc
 	 */
 	public IMarkupFragment findMarkupInAssociatedFileHeader(final Component child)
 	{
+		// Get the associated markup
 		IMarkupFragment markup = getAssociatedMarkup();
 		IMarkupFragment childMarkup = null;
+
+		// MarkupStream is good at searching markup
 		MarkupStream stream = new MarkupStream(markup);
 		while (stream.skipUntil(ComponentTag.class) && (childMarkup == null))
 		{
 			ComponentTag tag = stream.getTag();
-			if (tag instanceof WicketTag)
+			if (TagUtils.isWicketHeadTag(tag))
 			{
-				WicketTag wtag = (WicketTag)tag;
-				if (wtag.isHeadTag())
+				if (tag.getMarkupClass() == null)
 				{
-					if (tag.getMarkupClass() == null)
-					{
-						childMarkup = stream.getMarkupFragment().find(child.getId());
-					}
+					// find() can still fail an return null => continue the search
+					childMarkup = stream.getMarkupFragment().find(child.getId());
 				}
 			}
 			else if (TagUtils.isHeadTag(tag))
 			{
+				// find() can still fail an return null => continue the search
 				childMarkup = stream.getMarkupFragment().find(child.getId());
 			}
 
+			// Must be a direct child. We are not interested in grand children
 			if (tag.isOpen() && !tag.hasNoCloseTag())
 			{
 				stream.skipToMatchingCloseTag(tag);

Added: wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_20.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_20.html?rev=1042202&view=auto
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_20.html (added)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPageExpectedResult_20.html Sat Dec  4 15:13:38 2010
@@ -0,0 +1,21 @@
+<!--
+    ====================================================================
+    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.
+-->
+<html xmlns:wicket>
+<!-- no header section -->
+<head>should be rendered only once</head><body>
+	<span wicket:id="label1"></span>
+	<span wicket:id="label2"></span>
+</body>
+</html>

Added: wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.html?rev=1042202&view=auto
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.html (added)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.html Sat Dec  4 15:13:38 2010
@@ -0,0 +1,21 @@
+<!--
+    ====================================================================
+    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.
+-->
+<html xmlns:wicket>
+<!-- no header section -->
+<body>
+	<span wicket:id="label1"></span>
+	<span wicket:id="label2"></span>
+</body>
+</html>

Added: wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.java?rev=1042202&view=auto
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.java (added)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionPage_20.java Sat Dec  4 15:13:38 2010
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.wicket.markup.parser.filter;
+
+import org.apache.wicket.markup.html.IHeaderResponse;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.basic.Label;
+
+/**
+ * 
+ */
+public class HeaderSectionPage_20 extends WebPage
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Construct.
+	 */
+	public HeaderSectionPage_20()
+	{
+		add(new MyLabel("label1"));
+		add(new MyLabel("label2"));
+	}
+
+	public static class MyLabel extends Label
+	{
+		public MyLabel(final String id)
+		{
+			super(id);
+		}
+
+		/**
+		 * @see org.apache.wicket.Component#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
+		 */
+		@Override
+		public void renderHead(IHeaderResponse response)
+		{
+			response.renderString("should be rendered only once");
+			super.renderHead(response);
+		}
+	}
+}

Modified: wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionTest.java?rev=1042202&r1=1042201&r2=1042202&view=diff
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionTest.java (original)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/parser/filter/HeaderSectionTest.java Sat Dec  4 15:13:38 2010
@@ -203,4 +203,12 @@ public class HeaderSectionTest extends W
 	{
 		executeTest(HeaderSectionPage_19.class, "HeaderSectionPageExpectedResult_19.html");
 	}
+
+	/**
+	 * @throws Exception
+	 */
+	public void testRenderHomePage_20() throws Exception
+	{
+		executeTest(HeaderSectionPage_20.class, "HeaderSectionPageExpectedResult_20.html");
+	}
 }