You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by iv...@apache.org on 2012/01/08 06:23:23 UTC

git commit: queuing: bring code from hierarchy-completion branch sans resolver support

Updated Branches:
  refs/heads/sandbox/queueing b3d52388b -> 30162c67c


queuing: bring code from hierarchy-completion branch sans resolver support


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/30162c67
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/30162c67
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/30162c67

Branch: refs/heads/sandbox/queueing
Commit: 30162c67c376ca85d1fcdde23d494ab4b57feb6d
Parents: b3d5238
Author: Igor Vaynberg <iv...@apache.org>
Authored: Sat Jan 7 21:23:09 2012 -0800
Committer: Igor Vaynberg <iv...@apache.org>
Committed: Sat Jan 7 21:23:09 2012 -0800

----------------------------------------------------------------------
 .../java/org/apache/wicket/MarkupContainer.java    |  221 ++++++++++++---
 1 files changed, 179 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/30162c67/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
index 7e5d4c9..1782281 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -20,8 +20,10 @@ import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Stack;
 
 import org.apache.wicket.markup.ComponentTag;
@@ -36,6 +38,7 @@ import org.apache.wicket.markup.MarkupType;
 import org.apache.wicket.markup.WicketTag;
 import org.apache.wicket.markup.html.border.Border;
 import org.apache.wicket.markup.html.internal.InlineEnclosure;
+import org.apache.wicket.markup.repeater.AbstractRepeater;
 import org.apache.wicket.markup.resolver.ComponentResolvers;
 import org.apache.wicket.model.IComponentInheritedModel;
 import org.apache.wicket.model.IModel;
@@ -346,77 +349,211 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 	@Override
 	void dequeue()
 	{
-		ArrayList<Component> queue = getMetaData(QUEUE);
-		if (queue == null)
+		/*
+		 * WARNING: THIS CODE IS EXTREMELY ROUGH AND DOES NOT FUNCTION IN THE SAME WAY THAT FINAL
+		 * CODE WILL. IT IS HERE ONLY SO VARIOUS TESTS CAN BE WRITTEN IN HierarchyCompletionTest TO
+		 * EXPLORE THIS IDEA
+		 */
+
+		class ComponentAndTag
+		{
+			ComponentTag tag;
+			MarkupContainer component;
+
+			public ComponentAndTag(ComponentTag tag, MarkupContainer component)
+			{
+				this.tag = tag;
+				this.component = component;
+			}
+		}
+
+		MarkupStream markup = null;
+
+		if (hasAssociatedMarkup())
 		{
+			markup = new MarkupStream(getMarkupSourcingStrategy().getMarkup(this, null));
+			// FIXME a hack to skip the first tag that does not resolve to any component such as
+			// wicket:panel or wicket:border
+			MarkupElement e = markup.get();
+			if (e instanceof WicketTag)
+			{
+				if (((WicketTag)e).isMajorWicketComponentTag())
+				{
+					markup.next();
+				}
+			}
+		}
+		else if (getParent() instanceof AbstractRepeater)
+		{
+			markup = new MarkupStream(getParent().getMarkup());
+
+			// skip the repeater tag, we only want to traverse the body
+			markup.next();
+		}
+		else
+		{
+			// we only complete the hierarchy of components with associated markup and direct
+			// children of repeaters. the rest of components should be inside the previous two
+			// types.
+
 			return;
 		}
 
+		// stack of components between the current tag in the markup and the markup's owner
+		Stack<ComponentAndTag> stack = new Stack<ComponentAndTag>();
 
-		while (!queue.isEmpty())
+		// current component is the root of the stack. it has no component tag.
+		stack.push(new ComponentAndTag(null, this));
+
+		ComponentTag tag = null;
+
+		Map<Component, MarkupContainer> lateAdd = new HashMap<Component, MarkupContainer>();
+
+		while (markup.hasMore())
 		{
-			Component resolved = dequeueChild(queue);
-			if (resolved == null)
+			if (tag != null)
 			{
-				// TODO message
-				throw new WicketRuntimeException("Could not unqueue any child with id");
+				// advance the markup stream if this is not the first time through
+				markup.next();
 			}
-			else
+			if (!markup.skipUntil(ComponentTag.class))
 			{
-				queue.remove(resolved);
+				// TODO error if stack is not empty
+				break;
 			}
-		}
 
-		setMetaData(QUEUE, null);
-	}
+			// the current markup tag
+			tag = (ComponentTag)markup.get();
 
-	private Component dequeueChild(ArrayList<Component> queue)
-	{
-		IMarkupFragment markup = getMarkup();
-		for (Component child : queue)
-		{
-			Stack<ComponentTag> stack = new Stack<ComponentTag>();
+			if (tag.isClose())
+			{
+				if (stack.isEmpty())
+				{
+					// we are now out of the markup owner's body markup, most likely on a
+					// </wicket:panel> or something similar, we are done
+					break;
+					// return;
+				}
+				stack.pop();
+				continue;
+			}
+
+			final MarkupContainer parent = stack.peek().component;
 
-			for (int i = 0, size = markup.size(); i < size; i++)
+			// attempt to find a child component that corresponds to the markup tag
+
+			// TODO this should be get or resolve so transparent things work
+			Component child = parent.get(tag.getId());
+			if (child == null)
 			{
-				MarkupElement e = markup.get(i);
-				if (e instanceof ComponentTag)
+				// try to deque a child component if one has not been found
+
+
+				for (int j = stack.size() - 1; j >= 0; j--)
 				{
-					ComponentTag ct = (ComponentTag)e;
-					if (ct.isClose())
+					// we try to find a queued component from the deepest nested parent all the way
+					// to the owner of the markup
+					ComponentAndTag cat = stack.get(j);
+					ArrayList<Component> queue = cat.component.getMetaData(QUEUE);
+					if (queue == null)
 					{
-						stack.pop();
 						continue;
 					}
-					stack.push(ct);
-					if (ct.getId().equals(child.getId()))
+
+					for (Component queued : queue)
 					{
-						Component parent = this;
-						for (int si = 0, ssize = stack.size(); si < ssize - 1; si++)
+						if (queued.getId().equals(tag.getId()))
 						{
-							parent = parent.get(stack.get(si).getId());
-							if (parent == null)
-							{
-								break;
-							}
-						}
-						if (parent != null)
-						{
-							((MarkupContainer)parent).add(child);
-							return child;
+							child = queued;
+							break;
 						}
-
 					}
-					if (ct.isOpenClose())
+					if (child != null)
+					{
+						queue.remove(child);
+						break;
+					}
+				}
+			}
+
+			if (child != null && child.getParent() == null)
+			{
+				if (parent.findParent(Page.class) != null)
+				{
+					// if the parent is linked to the page we will delay the lateadd call so
+					// onconfigure is now triggered on the child right away, but instead after its
+					// children have been resolved
+					lateAdd.put(child, parent);
+				}
+				else
+				{
+					parent.add(child);
+				}
+				// TODO do we need to continue unqueuing or can we skip this component
+				// and all its children if it has been deemed invisible? - dont think we can because
+				// that will leave components in the queue and ondetach() will bomb
+			}
+
+			if (child != null && child.isAuto())
+			{
+				// TODO this is yet another hack, need to figure out how auto components fit into
+				// this and why they dont get correctly resolved second time around
+				child.setAuto(false);
+			}
+
+			if (child == null)
+			{
+				// cannot resolve child component, error
+
+				// TODO make the mesage less queue-dependent. should be the same message that we
+				// throw during render when we cant resolve a child
+
+				String error = "Could not dequeue or resolve child: `" + tag.getId() + "`. ";
+				error += "Parent search stack: [";
+				for (int j = stack.size() - 1; j >= 0; j--)
+				{
+					if (j < stack.size() - 1)
 					{
-						stack.pop();
+						error += ", ";
 					}
+					ComponentAndTag cat = stack.get(j);
+					error += cat.component.getClass().getSimpleName() + "('" +
+						cat.component.getId() + "')";
 				}
+				error += "]";
+				throw new WicketRuntimeException(error);
+			}
+
+			if (tag.isOpenClose())
+			{
+				// if this is an open/close tag we are done
+				continue;
+			}
+
+			if (child instanceof AbstractRepeater)
+			{
+				// TODO hack for repeaters, this will be delegated to repeaters themselves later
+
+				// skip inner markup, it will be processed by repeater items
+				markup.skipToMatchingCloseTag(tag);
+			}
+			else if (child instanceof MarkupContainer)
+			{
+				stack.push(new ComponentAndTag(tag, (MarkupContainer)child));
+			}
+			else
+			{
+				// the child is not a container so we can skip its inner markup
+				markup.skipToMatchingCloseTag(tag);
 			}
 		}
-		return null;
+		for (Map.Entry<Component, MarkupContainer> delayed : lateAdd.entrySet())
+		{
+			delayed.getValue().add(delayed.getKey());
+		}
 	}
 
+
 	/**
 	 * @param component
 	 *            The component to check