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 2009/11/14 10:37:45 UTC

svn commit: r836148 - in /wicket/trunk/wicket/src: main/java/org/apache/wicket/ main/java/org/apache/wicket/markup/ main/java/org/apache/wicket/markup/html/ main/java/org/apache/wicket/markup/html/border/ main/java/org/apache/wicket/markup/html/form/ m...

Author: jdonnerstag
Date: Sat Nov 14 09:37:44 2009
New Revision: 836148

URL: http://svn.apache.org/viewvc?rev=836148&view=rev
Log:
wip on MarkupFragments; cleaning up old APIs

Added:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/OpenTagIterator.java
Modified:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/MarkupContainer.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/ComponentTag.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/IMarkupFragment.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/Markup.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupFragment.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/WebMarkupContainerWithAssociatedMarkup.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/border/Border.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponentPanel.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/internal/HtmlHeaderContainer.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.html
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java
    wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Panel.java
    wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/MarkupParserTest.java
    wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/html/panel/InlinePanelPage_5.java

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/MarkupContainer.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/MarkupContainer.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/MarkupContainer.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/MarkupContainer.java Sat Nov 14 09:37:44 2009
@@ -472,7 +472,7 @@
 		}
 
 		// Find the child's markup
-		markup = markup.find(null, child.getId(), 0);
+		markup = markup.find(child.getId(), 0);
 		if (markup != null)
 		{
 			return markup;

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/ComponentTag.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/ComponentTag.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/ComponentTag.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/ComponentTag.java Sat Nov 14 09:37:44 2009
@@ -70,9 +70,6 @@
 	 */
 	private String id;
 
-	/** The component's path in the markup */
-	private String path;
-
 	/** True, if attributes have been modified or added */
 	private transient boolean modified = false;
 
@@ -434,7 +431,6 @@
 	{
 		dest.id = id;
 		dest.setHasNoCloseTag(hasNoCloseTag);
-		dest.setPath(path);
 		dest.setAutoComponentTag(autoComponent);
 		if (markupClassRef != null)
 		{
@@ -743,27 +739,6 @@
 	}
 
 	/**
-	 * Gets the component path of wicket elements
-	 * 
-	 * @return path
-	 */
-	public String getPath()
-	{
-		return path;
-	}
-
-	/**
-	 * Sets the component path of wicket elements
-	 * 
-	 * @param path
-	 *            path
-	 */
-	void setPath(final String path)
-	{
-		this.path = path;
-	}
-
-	/**
 	 * 
 	 * @return True if the HTML tag (e.g. br) has no close tag
 	 */

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/IMarkupFragment.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/IMarkupFragment.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/IMarkupFragment.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/IMarkupFragment.java Sat Nov 14 09:37:44 2009
@@ -65,7 +65,7 @@
 	 *            Index to start searching
 	 * @return -1, if not found
 	 */
-	int findComponentIndex(final String path, final String id, final int startIndex);
+	int findComponentIndex(final String id, final int startIndex);
 
 	/**
 	 * Find the markup element index of the component with 'path'
@@ -78,7 +78,7 @@
 	 *            Index to start searching
 	 * @return -1, if not found
 	 */
-	IMarkupFragment find(final String path, final String id, final int startIndex);
+	IMarkupFragment find(final String id, final int startIndex);
 
 	/**
 	 * 

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/Markup.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/Markup.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/Markup.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/Markup.java Sat Nov 14 09:37:44 2009
@@ -18,15 +18,12 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.apache.wicket.util.resource.IFixedLocationResourceStream;
 import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.apache.wicket.util.string.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,15 +51,6 @@
 	/** The associated markup file */
 	private final MarkupResourceStream markupResourceStream;
 
-	/** A cache which maps (componentPath + id) to the componentTags index in the markup */
-	private Map<String, Integer> componentMap;
-
-	/**
-	 * Used at markup load time to maintain the current component path (not id) while adding markup
-	 * elements to this Markup instance
-	 */
-	private StringBuffer currentPath;
-
 	/**
 	 * Private Constructor for NO_MARKUP only
 	 */
@@ -160,160 +148,42 @@
 		}
 
 		markupElements = Collections.unmodifiableList(markupElements);
-		initialize();
-	}
-
-	/**
-	 * Add the tag to the local cache if open or open-close and if wicket:id is present
-	 * 
-	 * @param index
-	 * @param tag
-	 */
-	private void addToCache(final int index, final ComponentTag tag)
-	{
-		// Only if the tag has wicket:id="xx" and open or open-close
-		if ((tag.isOpen() || tag.isOpenClose()) &&
-			tag.getAttributes().containsKey(getMarkupResourceStream().getWicketId()))
-		{
-			// Add the tag to the cache
-			if (componentMap == null)
-			{
-				componentMap = new HashMap<String, Integer>();
-			}
-
-			/*
-			 * XXX cleanup - this fragment check probably needs to be in
-			 * componenttag.isWantToBeDirectMarkupChild() or something similar instead of being here
-			 */
-			final boolean fragment = (tag instanceof WicketTag && ((WicketTag)tag).isFragementTag());
-
-			final String key;
-
-			if (tag.getPath() != null && !fragment/* WICKET-404 */)
-			{
-				key = tag.getPath() + ":" + tag.getId();
-			}
-			else
-			{
-				key = tag.getId();
-			}
-			componentMap.put(key, new Integer(index));
-		}
-	}
-
-	/**
-	 * Set the components path within the markup and add the component tag to the local cache
-	 * 
-	 * @param componentPath
-	 * @param tag
-	 * @return componentPath
-	 */
-	private StringBuffer setComponentPathForTag(final StringBuffer componentPath,
-		final ComponentTag tag)
-	{
-		// Only if the tag has wicket:id="xx" and open or open-close
-		if ((tag.isOpen() || tag.isOpenClose()) &&
-			tag.getAttributes().containsKey(markupResourceStream.getWicketId()))
-		{
-			// With open-close the path does not change. It can/will not have
-			// children. The same is true for HTML tags like <br> or <img>
-			// which might not have close tags.
-			if (tag.isOpenClose() || tag.hasNoCloseTag())
-			{
-				// Set the components path.
-				if ((currentPath != null) && (currentPath.length() > 0))
-				{
-					tag.setPath(currentPath.toString());
-				}
-			}
-			else
-			{
-				// Set the components path.
-				if (currentPath == null)
-				{
-					currentPath = new StringBuffer(100);
-				}
-				else if (currentPath.length() > 0)
-				{
-					tag.setPath(currentPath.toString());
-					currentPath.append(':');
-				}
-
-				// .. and append the tags id to the component path for the
-				// children to come
-				currentPath.append(tag.getId());
-			}
-		}
-		else if (tag.isClose() && (currentPath != null))
-		{
-			// For example <wicket:message> does not have an id
-			if ((tag.getOpenTag() == null) ||
-				tag.getOpenTag().getAttributes().containsKey(markupResourceStream.getWicketId()))
-			{
-				// Remove the last element from the component path
-				int index = currentPath.lastIndexOf(":");
-				if (index != -1)
-				{
-					currentPath.setLength(index);
-				}
-				else
-				{
-					currentPath.setLength(0);
-				}
-			}
-		}
-
-		return currentPath;
 	}
 
 	/**
 	 * @see org.apache.wicket.markup.IMarkupFragment#findComponentIndex(java.lang.String,
 	 *      java.lang.String, int)
 	 */
-	public final int findComponentIndex(final String path, final String id, final int startIndex)
+	public final int findComponentIndex(final String id, final int startIndex)
 	{
-		if ((id == null) || (id.length() == 0))
-		{
-			throw new IllegalArgumentException("Parameter 'id' must not be null");
-		}
-
-		// TODO Post 1.2: A component path e.g. "panel:label" does not match 1:1
-		// with the markup in case of ListView, where the path contains a number
-		// for each list item. E.g. list:0:label. What we currently do is simply
-		// remove the number from the path and hope that no user uses an integer
-		// for a component id. This is a hack only. A much better solution would
-		// delegate to the various components recursively to search within there
-		// realm only for the components markup. ListItems could then simply
-		// do nothing and delegate to their parents.
-		String completePath = (path == null || path.length() == 0 ? id : path + ":" + id);
-
-		// s/:\d+//g
-		Pattern re = Pattern.compile(":\\d+");
-		Matcher matcher = re.matcher(completePath);
-		completePath = matcher.replaceAll("");
-
-		// All component tags are registered with the cache
-		if (componentMap != null)
+		if (Strings.isEmpty(id))
 		{
-			final Integer value = componentMap.get(completePath);
-			if (value != null)
-			{
-				// return the components position in the markup stream
-				return value.intValue();
-			}
+			throw new IllegalArgumentException("Parameter 'id' must not be null or empty");
 		}
 
-		for (int i = Math.max(0, startIndex); i < size(); i++)
+		MarkupStream stream = new MarkupStream(this);
+		stream.setCurrentIndex(Math.max(0, startIndex));
+		while (stream.hasMore())
 		{
-			MarkupElement elem = get(i);
+			MarkupElement elem = stream.get();
 			if (elem instanceof ComponentTag)
 			{
-				ComponentTag tag = (ComponentTag)elem;
-				if (tag.isAutoComponentTag() && (tag.getId() != null) && tag.getId().startsWith(id))
+				ComponentTag tag = stream.getTag();
+				if (tag.isOpen() || tag.isOpenClose())
 				{
-					return i;
+					if (tag.getId().equals(id))
+					{
+						return stream.getCurrentIndex();
+					}
+					if (tag.isOpen() && !tag.hasNoCloseTag() && !(tag instanceof WicketTag) &&
+						!"head".equals(tag.getName()) && !tag.isAutoComponentTag())
+					{
+						stream.skipToMatchingCloseTag(tag);
+					}
 				}
 			}
+
+			stream.next();
 		}
 
 		return -1;
@@ -324,9 +194,9 @@
 	 * @param that
 	 * @return true, if equal
 	 */
-	public final IMarkupFragment find(final String path, final String id, final int startIndex)
+	public final IMarkupFragment find(final String id, final int startIndex)
 	{
-		int index = findComponentIndex(path, id, startIndex);
+		int index = findComponentIndex(id, startIndex);
 		if (index >= 0)
 		{
 			return new MarkupFragment(this, index);
@@ -335,42 +205,6 @@
 	}
 
 	/**
-	 * Initialize the index where wicket tags can be found
-	 */
-	protected final void initialize()
-	{
-		// Reset
-		componentMap = null;
-
-		if (markupElements != null)
-		{
-			// HTML tags like <img> may not have a close tag. But because that
-			// can only be detected until later on in the sequential markup
-			// reading loop, we only can do it now.
-			StringBuffer componentPath = null;
-			for (int i = 0; i < size(); i++)
-			{
-				MarkupElement elem = get(i);
-				if (elem instanceof ComponentTag)
-				{
-					ComponentTag tag = (ComponentTag)elem;
-
-					// Set the tags components path
-					componentPath = setComponentPathForTag(componentPath, tag);
-
-					// and add it to the local cache to be found fast if
-					// required
-					addToCache(i, tag);
-				}
-			}
-		}
-
-		// The variable is only needed while adding markup elements.
-		// initialize() is invoked after all elements have been added.
-		currentPath = null;
-	}
-
-	/**
 	 * @see org.apache.wicket.markup.IMarkupFragment#toString()
 	 */
 	@Override

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupFragment.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupFragment.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupFragment.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupFragment.java Sat Nov 14 09:37:44 2009
@@ -17,6 +17,7 @@
 package org.apache.wicket.markup;
 
 import org.apache.wicket.util.string.AppendingStringBuffer;
+import org.apache.wicket.util.string.Strings;
 
 /**
  * Represents a portion of a markup file, but always spans a complete tag. E.g.
@@ -43,9 +44,6 @@
 	/** The size of the fragment (usually from open to close tag) */
 	private final int size;
 
-	/** the component id of the start tag */
-	private final String rootPath;
-
 	/**
 	 * Construct.
 	 * 
@@ -127,26 +125,6 @@
 		}
 
 		size = endIndex - startIndex + 1;
-
-		// @TODO Setting the rootPath depending on specific tags is really ugly, since there is
-		// no way for user to enhance it in case he creates its own wicket tag. It probably can
-		// be removed once we switch to the markup resolution process.
-		if (startTag instanceof WicketTag)
-		{
-			WicketTag tag = (WicketTag)startTag;
-			if (tag.isFragementTag() || tag.isContainerTag())
-			{
-				rootPath = startTag.getId();
-			}
-			else
-			{
-				rootPath = null;
-			}
-		}
-		else
-		{
-			rootPath = startTag.getId();
-		}
 	}
 
 	/**
@@ -168,18 +146,35 @@
 	 * @see org.apache.wicket.markup.IMarkupFragment#findComponentIndex(java.lang.String,
 	 *      java.lang.String)
 	 */
-	public final int findComponentIndex(String path, final String id, final int startIndex)
+	public final int findComponentIndex(final String id, final int startIndex)
 	{
-		// Prepend rootPath to the 'path' parameter
-		path = (path == null ? rootPath : (rootPath == null ? path : rootPath + ":" + path));
-
-		// Search the markup
-		int index = markup.findComponentIndex(path, id, this.startIndex + startIndex) -
-			this.startIndex;
+		if (Strings.isEmpty(id))
+		{
+			throw new IllegalArgumentException("Parameter 'id' must not be null or empty");
+		}
 
-		if ((index >= 0) && (index < size))
+		MarkupStream stream = new MarkupStream(this);
+		stream.setCurrentIndex(Math.max(1, startIndex));
+		while (stream.hasMore())
 		{
-			return index;
+			MarkupElement elem = stream.get();
+			if (elem instanceof ComponentTag)
+			{
+				ComponentTag tag = stream.getTag();
+				if (tag.isOpen() || tag.isOpenClose())
+				{
+					if (tag.getId().equals(id))
+					{
+						return stream.getCurrentIndex();
+					}
+					if (tag.isOpen() && !tag.hasNoCloseTag() && !(tag instanceof WicketTag))
+					{
+						stream.skipToMatchingCloseTag(tag);
+					}
+				}
+			}
+
+			stream.next();
 		}
 
 		return -1;
@@ -188,9 +183,9 @@
 	/**
 	 * @see org.apache.wicket.markup.IMarkupFragment#find(java.lang.String, java.lang.String, int)
 	 */
-	public final IMarkupFragment find(final String path, final String id, final int startIndex)
+	public final IMarkupFragment find(final String id, final int startIndex)
 	{
-		int index = findComponentIndex(path, id, startIndex);
+		int index = findComponentIndex(id, startIndex);
 		if (index >= 0)
 		{
 			return new MarkupFragment(this, index);

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MarkupStream.java Sat Nov 14 09:37:44 2009
@@ -196,9 +196,9 @@
 	 *            The component's id to search for
 	 * @return -1, if not found
 	 */
-	public final int findComponentIndex(final String path, final String id)
+	public final int findComponentIndex(final String id)
 	{
-		return markup.findComponentIndex(path, id, 0);
+		return markup.findComponentIndex(id, 0);
 	}
 
 	/**
@@ -324,6 +324,29 @@
 	}
 
 	/**
+	 * Note:
+	 * 
+	 * @return The next markup element in the stream
+	 */
+	public MarkupElement nextOpenTag()
+	{
+		while (next() != null)
+		{
+			MarkupElement elem = get();
+			if (elem instanceof ComponentTag)
+			{
+				ComponentTag tag = (ComponentTag)elem;
+				if (tag.isOpen() || tag.isOpenClose())
+				{
+					return current = get(currentIndex);
+				}
+			}
+		}
+
+		return null;
+	}
+
+	/**
 	 * @param currentIndex
 	 *            New current index in the stream
 	 */

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/MergedMarkup.java Sat Nov 14 09:37:44 2009
@@ -78,9 +78,6 @@
 		// Merge derived and base markup
 		merge(markup, baseMarkup, extendIndex);
 
-		// Initialize internals based on new markup
-		initialize();
-
 		if (log.isDebugEnabled())
 		{
 			log.debug("Merge markup: " + toString());

Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/OpenTagIterator.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/OpenTagIterator.java?rev=836148&view=auto
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/OpenTagIterator.java (added)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/OpenTagIterator.java Sat Nov 14 09:37:44 2009
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import java.util.Iterator;
+
+/**
+ * @author Juergen Donnerstag
+ */
+public class OpenTagIterator implements Iterator<ComponentTag>
+{
+	private final IMarkupFragment markup;
+
+	private int index = -1;
+
+	/**
+	 * Construct.
+	 * 
+	 * @param markup
+	 */
+	public OpenTagIterator(final IMarkupFragment markup)
+	{
+		this.markup = markup;
+	}
+
+	/**
+	 * @see java.util.Iterator#hasNext()
+	 */
+	public boolean hasNext()
+	{
+		while (++index < markup.size())
+		{
+			MarkupElement elem = markup.get(index);
+			if (elem instanceof ComponentTag)
+			{
+				ComponentTag tag = (ComponentTag)elem;
+				if (tag.isOpen() || tag.isOpenClose())
+				{
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * @see java.util.Iterator#next()
+	 */
+	public ComponentTag next()
+	{
+		return (index < markup.size() ? (ComponentTag)markup.get(index) : null);
+	}
+
+	/**
+	 * 
+	 * @return MarkupFragment
+	 */
+	public final IMarkupFragment getMarkupFragment()
+	{
+		return new MarkupFragment(markup, index);
+	}
+
+	/**
+	 * @see java.util.Iterator#remove()
+	 */
+	public void remove()
+	{
+		throw new UnsupportedOperationException("remove() is not supported");
+	}
+}

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=836148&r1=836147&r2=836148&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 Nov 14 09:37:44 2009
@@ -17,6 +17,9 @@
 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.OpenTagIterator;
 import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
 import org.apache.wicket.model.IModel;
 
@@ -24,7 +27,6 @@
  * WebMarkupContainer with it's own markup and possibly <wicket:head> tag.
  * 
  * @author Juergen Donnerstag
- * 
  */
 public class WebMarkupContainerWithAssociatedMarkup extends WebMarkupContainer
 	implements
@@ -81,4 +83,35 @@
 	{
 		return new HeaderPartContainer(id, this, scope);
 	}
+
+	/**
+	 * Search the child's markup in the header section of the markup
+	 * 
+	 * @param markup
+	 * @param child
+	 * @return Null, if not found
+	 */
+	public IMarkupFragment findMarkupInAssociatedFileHeader(final IMarkupFragment markup,
+		final Component child)
+	{
+		IMarkupFragment childMarkup = null;
+		OpenTagIterator iter = new OpenTagIterator(markup);
+		while (iter.hasNext() && (childMarkup == null))
+		{
+			ComponentTag tag = iter.next();
+			if ((child != null) && "_header_".equals(tag.getId()))
+			{
+				childMarkup = iter.getMarkupFragment().find(child.getId(), 0);
+			}
+			else if ((child != null) && "_head".equals(tag.getId()))
+			{
+				if (tag.getMarkupClass() == null)
+				{
+					childMarkup = iter.getMarkupFragment().find(child.getId(), 0);
+				}
+			}
+		}
+
+		return childMarkup;
+	}
 }
\ No newline at end of file

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/border/Border.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/border/Border.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/border/Border.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/border/Border.java Sat Nov 14 09:37:44 2009
@@ -414,15 +414,27 @@
 			return new MarkupFragment(markup, i);
 		}
 
+		IMarkupFragment childMarkup = null;
+
 		// Since we created the body component instance, identifying that we found it is easy.
 		if (child == body)
 		{
 			// Find the markup for the child component. Make sure you use the preset default value.
-			return markup.find(null, BODY_ID, i);
+			childMarkup = markup.find(BODY_ID, i);
+			if (childMarkup != null)
+			{
+				return childMarkup;
+			}
 		}
 
 		// Find the markup for the child component
-		return markup.find(null, child.getId(), i);
+		childMarkup = markup.find(child.getId(), i);
+		if (childMarkup != null)
+		{
+			return childMarkup;
+		}
+
+		return findMarkupInAssociatedFileHeader(markup, child);
 	}
 
 	/**
@@ -534,7 +546,7 @@
 				return markup;
 			}
 
-			return markup.find(null, child.getId(), 0);
+			return markup.find(child.getId(), 0);
 		}
 	}
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponentPanel.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponentPanel.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponentPanel.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/form/FormComponentPanel.java Sat Nov 14 09:37:44 2009
@@ -247,7 +247,7 @@
 		}
 
 		// Find <wicket:panel>
-		int index = markup.findComponentIndex(null, "_panel", 0);
+		int index = markup.findComponentIndex("_panel", 0);
 		if (index == -1)
 		{
 			throw new MarkupException(
@@ -262,6 +262,6 @@
 		}
 
 		// else, find the markup fragment for the child component
-		return markup.find(null, child.getId(), index);
+		return markup.find(child.getId(), index);
 	}
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/internal/HtmlHeaderContainer.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/internal/HtmlHeaderContainer.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/internal/HtmlHeaderContainer.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/internal/HtmlHeaderContainer.java Sat Nov 14 09:37:44 2009
@@ -27,8 +27,8 @@
 import org.apache.wicket.Response;
 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.MarkupFragment;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.html.IHeaderResponse;
 import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -350,16 +350,32 @@
 		}
 
 		// wicket id can be either "_header_" or "_head"
-		int index1 = markup.findComponentIndex(null, "_header_", 0);
-		int index2 = markup.findComponentIndex(null, "_head", 0);
-		if (((ComponentTag)markup.get(index2)).getMarkupClass() != null)
-		{
-			index2 = -1;
-		}
-		int index = (index1 == -1 ? index2 : (index2 == -1) ? index1 : Math.min(index1, index2));
-		if (index >= 0)
+
+		// Find the markup fragment
+		MarkupStream stream = new MarkupStream(markup);
+		while (stream.hasMore())
 		{
-			return new MarkupFragment(markup, index);
+			MarkupElement elem = stream.get();
+			if (elem instanceof ComponentTag)
+			{
+				ComponentTag tag = stream.getTag();
+				if (tag.isOpen() || tag.isOpenClose())
+				{
+					if (tag.getId().equals("_header_"))
+					{
+						return stream.getMarkupFragment();
+					}
+					if (tag.getId().equals("_head"))
+					{
+						if (tag.getMarkupClass() == null)
+						{
+							return stream.getMarkupFragment();
+						}
+					}
+				}
+			}
+
+			stream.next();
 		}
 
 		return null;

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.html?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.html (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.html Sat Nov 14 09:37:44 2009
@@ -44,6 +44,11 @@
 		</p>
 		<table><tr><td><pre><span class="markup" wicket:id="markup">markup goes here</span></pre></td></tr></table>
 	</span>
+	
+	<span>
+		<h2>Stacktrace</h2>
+		<table><tr><td><pre><span class="markup" wicket:id="stacktrace">stacktrace goes here</span></pre></td></tr></table>
+	</span>
 
 	<p>
 	  <a href="#" wicket:id="displayPageViewLink">display page view</a>

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/pages/ExceptionErrorPage.java Sat Nov 14 09:37:44 2009
@@ -16,9 +16,13 @@
  */
 package org.apache.wicket.markup.html.pages;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.wicket.Page;
+import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.markup.MarkupException;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -28,7 +32,7 @@
 import org.apache.wicket.markup.html.debug.PageView;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.protocol.http.WebResponse;
-import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.string.AppendingStringBuffer;
 
 
 /**
@@ -56,7 +60,9 @@
 		this.throwable = throwable;
 
 		// Add exception label
-		add(new MultiLineLabel("exception", Strings.toString(throwable)));
+		add(new MultiLineLabel("exception", getErrorMessage(throwable)));
+
+		add(new MultiLineLabel("stacktrace", getStackTrace(throwable)));
 
 		// Get values
 		String resource = "";
@@ -105,6 +111,140 @@
 	}
 
 	/**
+	 * Converts a Throwable to a string.
+	 * 
+	 * @param throwable
+	 *            The throwable
+	 * @return The string
+	 */
+	public String getErrorMessage(final Throwable throwable)
+	{
+		if (throwable != null)
+		{
+			List<Throwable> al = convertToList(throwable);
+
+			AppendingStringBuffer sb = new AppendingStringBuffer(256);
+
+			// first print the last cause
+			int length = al.size() - 1;
+			Throwable cause = al.get(length);
+			if (throwable instanceof WicketRuntimeException)
+			{
+				String msg = throwable.getMessage();
+				if (throwable instanceof MarkupException)
+				{
+					MarkupStream stream = ((MarkupException)throwable).getMarkupStream();
+					if (stream != null)
+					{
+						String text = "\n" + stream.toString();
+						if (msg.endsWith(text))
+						{
+							msg = msg.substring(0, msg.length() - text.length());
+						}
+					}
+				}
+
+				sb.append("WicketMessage: ");
+				sb.append(msg);
+				sb.append("\n\n");
+			}
+			return sb.toString();
+		}
+		else
+		{
+			return "[Unknown]";
+		}
+	}
+
+	/**
+	 * Converts a Throwable to a string.
+	 * 
+	 * @param throwable
+	 *            The throwable
+	 * @return The string
+	 */
+	public String getStackTrace(final Throwable throwable)
+	{
+		if (throwable != null)
+		{
+			List<Throwable> al = convertToList(throwable);
+
+			AppendingStringBuffer sb = new AppendingStringBuffer(256);
+
+			// first print the last cause
+			int length = al.size() - 1;
+			Throwable cause = al.get(length);
+
+			sb.append("Root cause:\n\n");
+			outputThrowable(cause, sb, false);
+
+			if (length > 0)
+			{
+				sb.append("\n\nComplete stack:\n\n");
+				for (int i = 0; i < length; i++)
+				{
+					outputThrowable(al.get(i), sb, true);
+					sb.append("\n");
+				}
+			}
+			return sb.toString();
+		}
+		else
+		{
+			return "<Null Throwable>";
+		}
+	}
+
+	/**
+	 * @param throwable
+	 * @return xxx
+	 */
+	private List<Throwable> convertToList(final Throwable throwable)
+	{
+		List<Throwable> al = new ArrayList<Throwable>();
+		Throwable cause = throwable;
+		al.add(cause);
+		while (cause.getCause() != null && cause != cause.getCause())
+		{
+			cause = cause.getCause();
+			al.add(cause);
+		}
+		return al;
+	}
+
+	/**
+	 * Outputs the throwable and its stacktrace to the stringbuffer. If stopAtWicketSerlvet is true
+	 * then the output will stop when the org.apache.wicket servlet is reached. sun.reflect.
+	 * packages are filtered out.
+	 * 
+	 * @param cause
+	 * @param sb
+	 * @param stopAtWicketServlet
+	 */
+	private void outputThrowable(Throwable cause, AppendingStringBuffer sb,
+		boolean stopAtWicketServlet)
+	{
+		sb.append(cause);
+		sb.append("\n");
+		StackTraceElement[] trace = cause.getStackTrace();
+		for (int i = 0; i < trace.length; i++)
+		{
+			String traceString = trace[i].toString();
+			if (!(traceString.startsWith("sun.reflect.") && i > 1))
+			{
+				sb.append("     at ");
+				sb.append(traceString);
+				sb.append("\n");
+				if (stopAtWicketServlet &&
+					(traceString.startsWith("org.apache.wicket.protocol.http.WicketServlet") || traceString.startsWith("org.apache.wicket.protocol.http.WicketFilter")))
+				{
+					return;
+				}
+			}
+		}
+	}
+
+	/**
 	 * @see org.apache.wicket.markup.html.WebPage#configureResponse()
 	 */
 	@Override

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java Sat Nov 14 09:37:44 2009
@@ -20,6 +20,7 @@
 import org.apache.wicket.MarkupContainer;
 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.MarkupNotFoundException;
 import org.apache.wicket.markup.MarkupStream;
@@ -203,13 +204,29 @@
 	 */
 	private void renderFragment(final MarkupStream providerMarkupStream, final ComponentTag openTag)
 	{
-		// remember the current position in the markup. Will have to come back
-		// to it.
+		// remember the current position in the markup. Will have to come back to it.
 		int currentIndex = providerMarkupStream.getCurrentIndex();
 
 		// Find the markup fragment
-		int index = providerMarkupStream.findComponentIndex(null, markupId);
-		if (index == -1)
+		while (providerMarkupStream.hasMore())
+		{
+			MarkupElement elem = providerMarkupStream.get();
+			if (elem instanceof ComponentTag)
+			{
+				ComponentTag tag = providerMarkupStream.getTag();
+				if (tag.isOpen() || tag.isOpenClose())
+				{
+					if (tag.getId().equals(markupId))
+					{
+						break;
+					}
+				}
+			}
+
+			providerMarkupStream.nextOpenTag();
+		}
+
+		if (providerMarkupStream.hasMore() == false)
 		{
 			throw new MarkupException("Markup of component class `" +
 				providerMarkupStream.getContainerClass().getName() +
@@ -217,9 +234,6 @@
 				toString());
 		}
 
-		// Set the markup stream position to where the fragment begins
-		providerMarkupStream.setCurrentIndex(index);
-
 		try
 		{
 			// Get the fragments open tag
@@ -245,27 +259,6 @@
 	}
 
 	/**
-	 * Position the markup stream at the child component relative to the <b>provider</b> markup
-	 * 
-	 * @param path
-	 * @return The markup stream for the given component.
-	 */
-	public MarkupStream findComponentIndex(final String path)
-	{
-		MarkupStream markupStream = getAssociatedMarkupStream(true);
-		int index = markupStream.findComponentIndex(markupId, path);
-		if (index == -1)
-		{
-			throw new MarkupException("Markup of component class `" +
-				markupStream.getContainerClass().getName() +
-				"` does not contain a fragment with wicket:id `" + markupId + "`. Context: " +
-				toString());
-		}
-		markupStream.setCurrentIndex(index);
-		return markupStream;
-	}
-
-	/**
 	 * @see org.apache.wicket.MarkupContainer#hasAssociatedMarkup()
 	 */
 	@Override
@@ -365,13 +358,13 @@
 			return null;
 		}
 
-		markup = markup.find(null, markupId, 0);
+		markup = markup.find(markupId, 0);
 
 		if (child == null)
 		{
 			return markup;
 		}
 
-		return markup.find(null, child.getId(), 0);
+		return markup.find(child.getId(), 0);
 	}
 }

Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Panel.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Panel.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Panel.java (original)
+++ wicket/trunk/wicket/src/main/java/org/apache/wicket/markup/html/panel/Panel.java Sat Nov 14 09:37:44 2009
@@ -156,7 +156,7 @@
 		}
 
 		// Find <wicket:panel>
-		int index = markup.findComponentIndex(null, "_panel", 0);
+		int index = markup.findComponentIndex("_panel", 0);
 		if (index == -1)
 		{
 			throw new MarkupNotFoundException(
@@ -171,6 +171,12 @@
 		}
 
 		// Find the markup for the child component
-		return markup.find(null, child.getId(), index);
+		IMarkupFragment childMarkup = markup.find(child.getId(), index);
+		if (childMarkup != null)
+		{
+			return childMarkup;
+		}
+
+		return findMarkupInAssociatedFileHeader(markup, child);
 	}
 }

Modified: wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/MarkupParserTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/MarkupParserTest.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/MarkupParserTest.java (original)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/MarkupParserTest.java Sat Nov 14 09:37:44 2009
@@ -407,14 +407,11 @@
 
 		ComponentTag t = (ComponentTag)markup.get(0);
 		assertEquals(t.getId(), "span");
-		assertEquals(t.getPath(), null);
 
 		t = (ComponentTag)markup.get(1);
 		assertEquals(t.getId(), "img");
-		assertEquals(t.getPath(), "span");
 
 		t = (ComponentTag)markup.get(2);
 		assertEquals(t.getId(), "span2");
-		assertEquals(t.getPath(), "span");
 	}
 }

Modified: wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/html/panel/InlinePanelPage_5.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/html/panel/InlinePanelPage_5.java?rev=836148&r1=836147&r2=836148&view=diff
==============================================================================
--- wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/html/panel/InlinePanelPage_5.java (original)
+++ wicket/trunk/wicket/src/test/java/org/apache/wicket/markup/html/panel/InlinePanelPage_5.java Sat Nov 14 09:37:44 2009
@@ -80,7 +80,7 @@
 				return markup;
 			}
 
-			return markup.find(null, child.getId(), 0);
+			return markup.find(child.getId(), 0);
 		}
 	}
 }