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 2014/02/16 06:56:23 UTC

git commit: dequeue docs

Repository: wicket
Updated Branches:
  refs/heads/sandbox/component-queueing-2 384d748c1 -> 3a3e32a59


dequeue docs


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

Branch: refs/heads/sandbox/component-queueing-2
Commit: 3a3e32a597aa312f97cc588a66780783cd0eb9ed
Parents: 384d748
Author: Igor Vaynberg <ig...@gmail.com>
Authored: Sat Feb 15 21:56:18 2014 -0800
Committer: Igor Vaynberg <ig...@gmail.com>
Committed: Sat Feb 15 21:56:18 2014 -0800

----------------------------------------------------------------------
 .../java/org/apache/wicket/DequeueContext.java  |  68 ++++++-
 .../java/org/apache/wicket/IQueueRegion.java    |  22 ++-
 .../java/org/apache/wicket/MarkupContainer.java | 190 ++++++++++---------
 .../wicket/markup/html/border/Border.java       |   8 +-
 .../markup/repeater/AbstractRepeater.java       |   4 +
 5 files changed, 188 insertions(+), 104 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java b/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
index 4e62c3e..c13b0f2 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
@@ -2,19 +2,26 @@ package org.apache.wicket;
 
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.IMarkupFragment;
-import org.apache.wicket.markup.Markup;
 import org.apache.wicket.markup.MarkupElement;
 import org.apache.wicket.util.collections.ArrayListStack;
 
-public class DequeueContext
+/**
+ * Context for component dequeueing. Keeps track of markup position and container stack.
+ * 
+ * @author igor
+ *
+ */
+public final class DequeueContext
 {
 	private final IMarkupFragment markup;
 	private int index;
 	private ComponentTag next;
 	private ArrayListStack<ComponentTag> tags = new ArrayListStack<>();
+
 	private ArrayListStack<MarkupContainer> containers = new ArrayListStack<>();
 
-	public static class Bookmark
+	/** A bookmark for the DequeueContext stack */
+	public static final class Bookmark
 	{
 		private final int index;
 		private final ComponentTag next;
@@ -45,21 +52,39 @@ public class DequeueContext
 		next=nextTag();
 	}
 	
+	/**
+	 * Saves the state of the context into a bookmark which can later be used to restore it.
+	 */
 	public Bookmark save()
 	{
 		return new Bookmark(this);
 	}
 
+	/**
+	 * Restores the state of the context from the bookmark
+	 * 
+	 * @param bookmark
+	 */
 	public void restore(Bookmark bookmark)
 	{
 		bookmark.restore(this);
 	}
 
+	/**
+	 * Peeks markup tag that would be retrieved by call to {@link #popTag()}
+	 * 
+	 * @return
+	 */
 	public ComponentTag peekTag()
 	{
 		return next;
 	}
 	
+	/**
+	 * Retrieves the next markup tag
+	 * 
+	 * @return
+	 */
 	public ComponentTag popTag()
 	{
 		ComponentTag taken=next;
@@ -68,6 +93,9 @@ public class DequeueContext
 		return taken;
 	}
 	
+	/**
+	 * Skips to the closing tag of the tag retrieved from last call to {@link #popTag()}
+	 */
 	public void skipToCloseTag()
 	{
 		if (tags.peek().isOpen())
@@ -89,7 +117,7 @@ public class DequeueContext
 			{
 				ComponentTag tag = (ComponentTag)element;
 				ComponentTag open = tag.isClose() ? tag.getOpenTag() : tag;
-				if (canDequeue(open))
+				if (canDequeueTag(open))
 				{
 					index++;
 					return tag;
@@ -99,7 +127,7 @@ public class DequeueContext
 		return null;
 	}
 	
-	private boolean canDequeue(ComponentTag open)
+	private boolean canDequeueTag(ComponentTag open)
 	{
 		if (containers.size() < 1)
 		{
@@ -108,7 +136,7 @@ public class DequeueContext
 		}
 		for (int i = containers.size() - 1; i >= 0; i--)
 		{
-			if (containers.get(i).supportsDequeueingFrom((open)))
+			if (containers.get(i).canDequeueTag((open)))
 			{
 				return true;
 			}
@@ -116,27 +144,53 @@ public class DequeueContext
 		return false;
 	}
 
+	/**
+	 * Checks if the tag returned by {@link #peekTag()} is either open or open-close.
+	 * 
+	 * @return
+	 */
 	public boolean isAtOpenOrOpenCloseTag()
 	{
 		return peekTag() != null && (peekTag().isOpen() || peekTag().isOpenClose());
 	}
 
+	/**
+	 * Retrieves the container on the top of the containers stack
+	 * 
+	 * @return
+	 */
 	public MarkupContainer peekContainer()
 	{
 		return containers.peek();
 	}
 
+	/**
+	 * Pushes a container onto the container stack
+	 * 
+	 * @param container
+	 */
 	public void pushContainer(MarkupContainer container)
 	{
 		containers.push(container);
 	}
 
+	/**
+	 * Pops a container from the container stack
+	 * 
+	 * @return
+	 */
 	public MarkupContainer popContainer()
 	{
 		return containers.pop();
 	}
 
-	public Component dequeue(ComponentTag tag)
+	/**
+	 * Searches the container stack for a component that can be dequeud
+	 * 
+	 * @param tag
+	 * @return
+	 */
+	public Component findComponentToDequeue(ComponentTag tag)
 	{
 		for (int j = containers.size() - 1; j >= 0; j--)
 		{

http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java b/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
index 86e30c6..beebdda 100644
--- a/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
+++ b/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
@@ -16,9 +16,11 @@
  */
 package org.apache.wicket;
 
+import org.apache.wicket.markup.IMarkupFragment;
+
 /**
- * Demarcates components that can dequeue children. These are usually components with associated
- * markup since the markup is needed to dequeue.
+ * Demarcates components that act as a root can dequeue children. These are usually components with
+ * associated markup since the markup is needed to dequeue.
  * 
  * It is also important to note that components queued outside of a region cannot be dequeued into
  * it since regions act as roots for the dequeue process because they contain the markup. As such,
@@ -30,5 +32,21 @@ package org.apache.wicket;
  */
 public interface IQueueRegion
 {
+	/**
+	 * Gets the markup that will be used to dequeue components in this container. Usually containers
+	 * will return their associated markup by simply delegating to
+	 * {@link MarkupContainer#getAssociatedMarkup()}, but compoennts that do not render markup in a
+	 * standard way (such as repeaters and borders) may choose to override this method to implement
+	 * custom behavior for the dequeuing process.
+	 */
+	public IMarkupFragment getDequeueMarkup();
 
+	/**
+	 * Starts component dequeueing on this {@link IQueueRegion}. This is the entry point into the
+	 * dequeuing process, it creates the {@link DequeueContext} and delegates the opreation to the
+	 * {@link #dequeue(DequeueContext)} method which performs the actual dequeuing. The context's
+	 * markup is retrieved using the {@link #getDequeueMarkup()} method which allows subclasses to
+	 * provide dequeueing-specific markup.
+	 */
+	public void dequeue();
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/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 e213f35..3fe7c98 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -36,13 +36,11 @@ 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;
 import org.apache.wicket.model.IWrapModel;
 import org.apache.wicket.settings.DebugSettings;
-import org.apache.wicket.util.collections.ArrayListStack;
 import org.apache.wicket.util.io.IClusterable;
 import org.apache.wicket.util.iterator.ComponentHierarchyIterator;
 import org.apache.wicket.util.lang.Args;
@@ -1519,22 +1517,28 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		super.onInitialize();
 		if (this instanceof IQueueRegion)
 		{
-			// dequeue auto components
-			Markup markup = getAssociatedMarkup();
-			if (markup != null)
+			// if this container is a queue region dequeue any queued up auto components
+			dequeueAutoComponents();
+		}
+	}
+
+	private void dequeueAutoComponents()
+	{
+		// dequeue auto components
+		IMarkupFragment markup = getDequeueMarkup();
+		if (markup != null)
+		{
+			// make sure we have markup, when running inside tests we wont
+			for (int i = 0; i < markup.size(); i++)
 			{
-				// make sure we have markup, when running inside tests we wont
-				for (int i = 0; i < markup.size(); i++)
+				MarkupElement element = markup.get(i);
+				if (element instanceof ComponentTag)
 				{
-					MarkupElement element = markup.get(i);
-					if (element instanceof ComponentTag)
+					ComponentTag tag = (ComponentTag)element;
+					if (tag.getAutoComponentFactory() != null)
 					{
-						ComponentTag tag = (ComponentTag)element;
-						if (tag.getAutoComponentFactory() != null)
-						{
-							Component auto = tag.getAutoComponentFactory().newComponent(tag);
-							queue(auto);
-						}
+						Component auto = tag.getAutoComponentFactory().newComponent(tag);
+						queue(auto);
 					}
 				}
 			}
@@ -1952,55 +1956,6 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		}
 	}
 
-	/**
-	 * Automatically create components for <wicket:xxx> tag.
-	 */
-	// to use it call it from #onInitialize()
-	private void createAndAddComponentsForWicketTags()
-	{
-		// Markup must be available
-		IMarkupFragment markup = getMarkup();
-		if ((markup != null) && (markup.size() > 1))
-		{
-			MarkupStream stream = new MarkupStream(markup);
-
-			// Skip the first component tag which already belongs to 'this' container
-			if (stream.skipUntil(ComponentTag.class))
-			{
-				stream.next();
-			}
-
-			// Search for <wicket:xxx> in the remaining markup and try to resolve the component
-			while (stream.skipUntil(ComponentTag.class))
-			{
-				ComponentTag tag = stream.getTag();
-				if (tag.isOpen() || tag.isOpenClose())
-				{
-					if (tag instanceof WicketTag)
-					{
-						Component component = ComponentResolvers.resolve(this, stream, tag, null);
-						if ((component != null) && (component.getParent() == null))
-						{
-							if (component.getId().equals(tag.getId()) == false)
-							{
-								// make sure we are able to get() the component during rendering
-								tag.setId(component.getId());
-								tag.setModified(true);
-							}
-							add(component);
-						}
-					}
-
-					if (tag.isOpen())
-					{
-						stream.skipToMatchingCloseTag(tag);
-					}
-				}
-				stream.next();
-			}
-		}
-	}
-
 	@Override
 	protected void onDetach()
 	{
@@ -2017,6 +1972,17 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 
 	private transient ComponentQueue queue;
 
+	/**
+	 * Queues a component to be dequeued later. The advantage of this method over the
+	 * {@link #add(Component...)} method is that the component does not have to be added to its
+	 * direct parent, only to a parent upstream; it will be dequeued into the correct parent using
+	 * the hierarchy defined in the markup. This allows the component hiearchy to be maintined only
+	 * in markup instead of in markup and in java code; affording designers and developers more
+	 * freedom when moving components in markup.
+	 * 
+	 * @param components
+	 * @return
+	 */
 	public MarkupContainer queue(Component... components)
 	{
 		if (queue == null)
@@ -2054,7 +2020,10 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		return this;
 	}
 
-	void dequeue()
+	/**
+	 * @see IQueueRegion#dequeue()
+	 */
+	public void dequeue()
 	{
 		if (!(this instanceof IQueueRegion))
 		{
@@ -2070,7 +2039,20 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		setRequestFlag(RFLAG_CONTAINER_DEQUEING, true);
 		try
 		{
-			internalDequeue();
+			IMarkupFragment markup = getDequeueMarkup();
+			if (markup == null)
+			{
+				// markup not found, skip dequeuing
+				// this sometimes happens when we are in a unit test
+				return;
+			}
+
+			DequeueContext dequeue = new DequeueContext(markup, this);
+
+			if (dequeue.peekTag() != null)
+			{
+				dequeue(dequeue);
+			}
 		}
 		finally
 		{
@@ -2078,29 +2060,23 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		}
 	}
 
-	private void internalDequeue()
-	{
-		IMarkupFragment markup = getDequeueMarkup();
-		if (markup == null)
-		{
-			// markup not found, skip dequeuing
-			// this sometimes happens when we are in a unit test
-			return;
-		}
-
-		DequeueContext dequeue = new DequeueContext(markup, this);
-
-		if (dequeue.peekTag() != null)
-		{
-			dequeue(dequeue);
-		}
-
-
-	}
+	/**
+	 * Dequeues components. The default implementation iterates direct children of this container
+	 * found in the markup (retrieved via {@link #getDequeueMarkup()}) and tries to find matching
+	 * components in queues filled by a call to {@link #queue(Component...)}. It then delegates the
+	 * dequeing to these children.
+	 * 
+	 * The provided {@link DequeueContext} is used to maintain the place in markup as well as the
+	 * stack of components whose queues will be searched. For example, before delegating the call to
+	 * a child the container will push the child onto the stack of components.
+	 * 
+	 * Certain components that implement custom markup behaviors (such as repeaters and borders)
+	 * override this method to bring dequeuing in line with their custom markup handling.
+	 * 
+	 * @param dequeue
+	 */
 	public void dequeue(DequeueContext dequeue)
 	{
-		
-
 		while (dequeue.isAtOpenOrOpenCloseTag())
 		{
 		
@@ -2117,7 +2093,7 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 				// the container does not yet have a child with this id, see if we can
 				// dequeue
 				
-				child = dequeue.dequeue(tag);
+				child = dequeue.findComponentToDequeue(tag);
 	
 				if (child != null)
 				{
@@ -2154,17 +2130,28 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 					throw new IllegalStateException();
 				}
 			}
-
-
 		}
 
 	}
 	
-	protected IMarkupFragment getDequeueMarkup() {
+	/** @see IQueueRegion#getDequeueMarkup() */
+	public IMarkupFragment getDequeueMarkup()
+	{
 		return getAssociatedMarkup();
 	}
 	
-	protected boolean supportsDequeueingFrom(ComponentTag tag) {
+	/**
+	 * Checks if this container can dequeue a child represented by the specified tag. This method
+	 * should be overridden when containers can dequeue components represented by non-standard tags.
+	 * For example, borders override this method and dequeue their body container when processing
+	 * the body tag.
+	 * 
+	 * By default all {@link ComponentTag}s are supported as well as {@link WicketTag}s that return
+	 * a non-null value from {@link WicketTag#getAutoComponentFactory()} method.
+	 * 
+	 * @param tag
+	 */
+	protected boolean canDequeueTag(ComponentTag tag) {
 		if (tag instanceof WicketTag) {
 			WicketTag wicketTag=(WicketTag)tag;
 			if (wicketTag.getAutoComponentFactory() != null)
@@ -2177,11 +2164,30 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		return true;
 	}
 	
+	/**
+	 * Queries this container to find a child that can be dequeued that matches the specified tag.
+	 * The default implementation will check if there is a component in the queue that has the same
+	 * id as a tag, but sometimes custom tags can be dequeued and in those situations this method
+	 * should be overridden.
+	 * 
+	 * @param tag
+	 * @return
+	 */
 	public Component findComponentToDequeue(ComponentTag tag)
 	{
 		return queue == null ? null : queue.remove(tag.getId());
 	}
 
+	/**
+	 * Adds a dequeued component to this container. This method should rarely be overridden becase
+	 * the common case of simply forwarding the component to
+	 * {@link MarkupContainer#add(Component...))} method should cover most cases. Components that
+	 * implement a custom hierarchy, such as borders, may wish to override it to support edge-case
+	 * non-standard behavior.
+	 * 
+	 * @param component
+	 * @param tag
+	 */
 	protected void addDequeuedComponent(Component component, ComponentTag tag) {
 		add(component);
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
index 54fa141..e916d18 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/border/Border.java
@@ -537,7 +537,8 @@ public abstract class Border extends WebMarkupContainer implements IComponentRes
 			return markup.find(child.getId());
 		}
 		
-		protected IMarkupFragment getDequeueMarkup() {
+		public IMarkupFragment getDequeueMarkup()
+		{
 			Border border=findParent(Border.class);
 			IMarkupFragment fragment=findParent(Border.class).getMarkup();
 			/*
@@ -614,12 +615,12 @@ public abstract class Border extends WebMarkupContainer implements IComponentRes
 	
 	
 	@Override
-	protected boolean supportsDequeueingFrom(ComponentTag tag) {
+	protected boolean canDequeueTag(ComponentTag tag) {
 		if ((tag instanceof WicketTag)&&((WicketTag)tag).isBodyTag()) {
 			return true;
 		}
 
-		return super.supportsDequeueingFrom(tag);
+		return super.canDequeueTag(tag);
 	}
 	
 	@Override
@@ -632,6 +633,7 @@ public abstract class Border extends WebMarkupContainer implements IComponentRes
 	
 	@Override
 	protected void addDequeuedComponent(Component component, ComponentTag tag) {
+		// components queued in border get dequeued into the border not into the body container
 		addToBorder(component);
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/3a3e32a5/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java b/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
index 134e239..2b1a4bb 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/repeater/AbstractRepeater.java
@@ -157,6 +157,10 @@ public abstract class AbstractRepeater extends WebMarkupContainer
 	@Override
 	public void dequeue(DequeueContext dequeue) {
 		if (size()>0) {
+			// essentially what we do is for every child replace the repeater with the child in
+			// dequeue container stack and run the dequeue on the child. we also take care to reset
+			// the state of the dequeue context after we process every child.
+
 			Bookmark bookmark=dequeue.save();
 			
 			for (Component child:this) {