Repository: wicket
Updated Branches:
  refs/heads/master cc5d56a50 -> 2008dfb70


WICKET-3335 refactor/cleanup component queueing - a clean way to ignore outer 
tags which is necessary for proper fragment and border support


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

Branch: refs/heads/master
Commit: 2008dfb7044f544d7b112cf4666dfacf42406b89
Parents: cc5d56a
Author: Igor Vaynberg <igor.vaynb...@gmail.com>
Authored: Mon Feb 24 22:28:03 2014 -0800
Committer: Igor Vaynberg <igor.vaynb...@gmail.com>
Committed: Mon Feb 24 22:28:03 2014 -0800

----------------------------------------------------------------------
 .../java/org/apache/wicket/DequeueContext.java  | 90 ++++++++++++++++++--
 .../org/apache/wicket/DequeueTagAction.java     | 11 +++
 .../java/org/apache/wicket/IQueueRegion.java    |  8 +-
 .../java/org/apache/wicket/MarkupContainer.java | 59 +++++++------
 .../wicket/markup/html/border/Border.java       | 59 ++-----------
 .../html/panel/DequeueMarkupFragment.java       |  6 ++
 .../wicket/markup/html/panel/Fragment.java      | 16 ++--
 .../wicket/queueing/ComponentQueueingTest.java  | 24 +++++-
 8 files changed, 168 insertions(+), 105 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/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 a5bb925..2717e8c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
+++ b/wicket-core/src/main/java/org/apache/wicket/DequeueContext.java
@@ -34,6 +34,8 @@ public final class DequeueContext
        private int index;
        private ComponentTag next;
        private ArrayListStack<ComponentTag> tags = new ArrayListStack<>();
+       private final boolean skipFirst;
+       private ComponentTag first;
 
        private ArrayListStack<MarkupContainer> containers = new 
ArrayListStack<>();
 
@@ -62,9 +64,10 @@ public final class DequeueContext
                }
        }
        
-       public DequeueContext(IMarkupFragment markup, MarkupContainer root)
+       public DequeueContext(IMarkupFragment markup, MarkupContainer root, 
boolean skipFirst)
        {
                this.markup = markup;
+               this.skipFirst = skipFirst;
                containers.push(root);
                next=nextTag();
        }
@@ -105,6 +108,12 @@ public final class DequeueContext
        public ComponentTag takeTag()
        {
                ComponentTag taken=next;
+
+               if (taken == null)
+               {
+                       return null;
+               }
+
                if (taken.isOpen() && !taken.hasNoCloseTag())
                {
                        tags.push(taken);
@@ -130,27 +139,89 @@ public final class DequeueContext
        
        private ComponentTag nextTag()
        {
+               if (skipFirst && first == null)
+               {
+                       for (; index < markup.size(); index++)
+                       {
+                               MarkupElement element = markup.get(index);
+                               if (element instanceof ComponentTag)
+                               {
+                                       first = (ComponentTag)element;
+                                       index++;
+                                       break;
+                               }
+                       }
+               }
+
                for (; index < markup.size(); index++)
                {
                        MarkupElement element = markup.get(index);
                        if (element instanceof ComponentTag)
                        {
                                ComponentTag tag = (ComponentTag)element;
-                               ComponentTag open = tag.isClose() ? 
tag.getOpenTag() : tag;
-                               if (open != null && canDequeueTag(open))
+
+                               if (tag.isOpen() || tag.isOpenClose())
                                {
-                                       index++;
-                                       return tag;
+                                       DequeueTagAction action = 
canDequeueTag(tag);
+                                       switch (action)
+                                       {
+                                               case IGNORE :
+                                                       continue;
+                                               case DEQUEUE :
+                                                       index++;
+                                                       return tag;
+                                               case SKIP : // skip to close tag
+                                                       boolean found = false;
+                                                       for (; index < 
markup.size(); index++)
+                                                       {
+                                                               if 
((markup.get(index) instanceof ComponentTag)
+                                                                       && 
((ComponentTag)markup.get(index)).closes(tag))
+                                                               {
+                                                                       found = 
true;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       if (!found)
+                                                       {
+                                                               throw new 
IllegalStateException(
+                                                                       "Could 
not find close tag for tag: " + tag);
+                                                       }
+
+                                       }
+                               }
+                               else
+                               {
+                                       // closed tag
+                                       ComponentTag open = tag.isClose() ? 
tag.getOpenTag() : tag;
+
+                                       if (skipFirst && first != null && open 
== first)
+                                       {
+                                               continue;
+                                       }
+
+                                       switch (canDequeueTag(open))
+                                       {
+                                               case DEQUEUE :
+                                                       index++;
+                                                       return tag;
+                                               case IGNORE :
+                                                       continue;
+                                               case SKIP :
+                                                       throw new 
IllegalStateException(
+                                                               "Should not see 
closed tag of skipped open tag: " + tag);
+                                       }
                                }
                        }
                }
                return null;
        }
        
-       private boolean canDequeueTag(ComponentTag open)
+       private DequeueTagAction canDequeueTag(ComponentTag open)
        {
                Args.notNull(open, "open");
 
+               DequeueTagAction action = null;
+
                if (containers.size() < 1)
                {
                        // TODO queueing message: called too early
@@ -158,12 +229,13 @@ public final class DequeueContext
                }
                for (int i = containers.size() - 1; i >= 0; i--)
                {
-                       if (containers.get(i).canDequeueTag((open)))
+                       action = containers.get(i).canDequeueTag((open));
+                       if (action != null)
                        {
-                               return true;
+                               return action;
                        }
                }
-               return false;
+               return DequeueTagAction.IGNORE;
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/wicket-core/src/main/java/org/apache/wicket/DequeueTagAction.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/DequeueTagAction.java 
b/wicket-core/src/main/java/org/apache/wicket/DequeueTagAction.java
new file mode 100644
index 0000000..5981cb1
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/DequeueTagAction.java
@@ -0,0 +1,11 @@
+package org.apache.wicket;
+
+public enum DequeueTagAction
+{
+       /** dequeue the tag */
+       DEQUEUE,
+       /** skip this tag and all its children */
+       SKIP,
+       /** ignore this tag, skip it but do not skip its children */
+       IGNORE;
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/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 c0e431a..4bad6f7 100644
--- a/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
+++ b/wicket-core/src/main/java/org/apache/wicket/IQueueRegion.java
@@ -16,7 +16,6 @@
  */
 package org.apache.wicket;
 
-import org.apache.wicket.markup.IMarkupFragment;
 
 /**
  * Demarcates components that act as a root can dequeue children. These are 
usually components with
@@ -33,13 +32,14 @@ import org.apache.wicket.markup.IMarkupFragment;
 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
+        * Creates a new {@link DequeueContext} that will be used to dequeue 
children of this region.
+        * 
+        * Usually containers will create a context with their associated 
markup by getting it via
         * {@link MarkupContainer#getAssociatedMarkup()}, but components 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 dequeueing process.
         */
-       public IMarkupFragment getDequeueMarkup();
+       public DequeueContext newDequeueContext();
 
        /**
         * Starts component dequeueing on this {@link IQueueRegion}. This is 
the entry point into the

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/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 1aba865..616654f 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -1525,21 +1525,14 @@ public abstract class MarkupContainer extends Component 
implements Iterable<Comp
        private void dequeueAutoComponents()
        {
                // dequeue auto components
-               IMarkupFragment markup = getDequeueMarkup();
-               if (markup != null)
+               DequeueContext context = newDequeueContext();
+               if (context != null && context.peekTag() != null)
                {
-                       // make sure we have markup, when running inside tests 
we wont
-                       for (int i = 0; i < markup.size(); i++)
+                       for (ComponentTag tag = context.takeTag(); tag != null; 
tag = context.takeTag())
                        {
-                               MarkupElement element = markup.get(i);
-                               if (element instanceof ComponentTag)
+                               if (tag.getAutoComponentFactory() != null)
                                {
-                                       ComponentTag tag = 
(ComponentTag)element;
-                                       if (tag.getAutoComponentFactory() != 
null)
-                                       {
-                                               Component auto = 
tag.getAutoComponentFactory().newComponent(tag);
-                                               queue(auto);
-                                       }
+                                       
queue(tag.getAutoComponentFactory().newComponent(tag));
                                }
                        }
                }
@@ -2039,16 +2032,13 @@ public abstract class MarkupContainer extends Component 
implements Iterable<Comp
                setRequestFlag(RFLAG_CONTAINER_DEQUEING, true);
                try
                {
-                       IMarkupFragment markup = getDequeueMarkup();
-                       if (markup == null)
+                       DequeueContext dequeue = newDequeueContext();
+                       if (dequeue == null)
                        {
-                               // markup not found, skip dequeuing
-                               // this sometimes happens when we are in a unit 
test
+                               // not ready to dequeue yet
                                return;
                        }
 
-                       DequeueContext dequeue = new DequeueContext(markup, 
this);
-
                        if (dequeue.peekTag() != null)
                        {
                                dequeue(dequeue);
@@ -2083,9 +2073,8 @@ public abstract class MarkupContainer extends Component 
implements Iterable<Comp
        
                        // see if child is already added to parent
 
-                       Component child = get(tag.getId()); // TODO queueing 
add this into findInQueue and
-                                                                               
                // rename it to dequeue
-       
+                       Component child = get(tag.getId());
+
                        if (child == null)
                        {
                                // the container does not yet have a child with 
this id, see if we can
@@ -2147,12 +2136,17 @@ public abstract class MarkupContainer extends Component 
implements Iterable<Comp
 
        }
        
-       /** @see IQueueRegion#getDequeueMarkup() */
-       public IMarkupFragment getDequeueMarkup()
+       /** @see IQueueRegion#newDequeueContext() */
+       public DequeueContext newDequeueContext()
        {
-               return getAssociatedMarkup();
+               Markup markup = getAssociatedMarkup();
+               if (markup == null)
+               {
+                       return null;
+               }
+               return new DequeueContext(markup, this, false);
        }
-       
+
        /**
         * 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.
@@ -2164,25 +2158,30 @@ public abstract class MarkupContainer extends Component 
implements Iterable<Comp
         * 
         * @param tag
         */
-       protected boolean canDequeueTag(ComponentTag tag)
+       protected DequeueTagAction canDequeueTag(ComponentTag tag)
        {
                if (tag instanceof WicketTag)
                {
                        WicketTag wicketTag = (WicketTag)tag;
                        if (wicketTag.isContainerTag())
                        {
-                               return true;
+                               return DequeueTagAction.DEQUEUE;
                        }
+                       else
                        if (wicketTag.getAutoComponentFactory() != null)
                        {
-                               return true;
+                               return DequeueTagAction.DEQUEUE;
+                       }
+                       else if (wicketTag.isFragmentTag())
+                       {
+                               return DequeueTagAction.SKIP;
                        }
                        else
                        {
-                               return false;
+                               return null; // dont know
                        }
                }
-               return true;
+               return DequeueTagAction.DEQUEUE;
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/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 a53b780..f60fc8a 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
@@ -17,6 +17,8 @@
 package org.apache.wicket.markup.html.border;
 
 import org.apache.wicket.Component;
+import org.apache.wicket.DequeueContext;
+import org.apache.wicket.DequeueTagAction;
 import org.apache.wicket.IQueueRegion;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.markup.ComponentTag;
@@ -538,7 +540,7 @@ public abstract class Border extends WebMarkupContainer 
implements IComponentRes
                }
 
                @Override
-               public IMarkupFragment getDequeueMarkup()
+               public DequeueContext newDequeueContext()
                {
                        Border border=findParent(Border.class);
                        IMarkupFragment fragment = border.getMarkup();
@@ -548,56 +550,7 @@ public abstract class Border extends WebMarkupContainer 
implements IComponentRes
                                return null;
                        }
 
-                       /*
-                        * we want to get the contents of the border here (the 
markup that
-                        * is represented by the body tag) to do this we need 
to strip the
-                        * tag that the border is attached to (usually the 
first tag)
-                        */
-
-                       int i = 0;
-                       while (i < fragment.size())
-                       {
-                               // TODO queueing Use 
fragment.find(border.getId()); instead ?!
-                               MarkupElement element = fragment.get(i);
-                               if (element instanceof ComponentTag
-                                               && 
((ComponentTag)element).getId().equals(border.getId()))
-                               {
-                                       break;
-                               }
-                               i++;
-                       }
-
-                       if (i >= fragment.size())
-                       {
-                               throw new IllegalStateException("Could not find 
starting border tag for border: "
-                                               + border.getId() + " in markup: 
" + fragment);
-                       }
-
-
-                       /*
-                        * (i) is now at the border tag, find the next 
component tag (the tag that will belong
-                        * to the first direct child
-                        */
-
-                       i++;
-                       while (i < fragment.size())
-                       {
-                               MarkupElement element = fragment.get(i);
-                               if (element instanceof ComponentTag)
-                               {
-                                       break;
-                               }
-                               i++;
-                       }
-
-                       ComponentTag tag = (ComponentTag)fragment.get(i);
-                       if (tag.isClose())
-                       {
-                               // this closes the border tag, border only has 
raw markup
-                               return null;
-                       }
-
-                       return new MarkupFragment(fragment, i);
+                       return new DequeueContext(fragment, this, true);
                }
 
                @Override
@@ -636,11 +589,11 @@ public abstract class Border extends WebMarkupContainer 
implements IComponentRes
        }
 
        @Override
-       protected boolean canDequeueTag(ComponentTag tag)
+       protected DequeueTagAction canDequeueTag(ComponentTag tag)
        {
                if ((tag instanceof WicketTag) && ((WicketTag)tag).isBodyTag())
                {
-                       return true;
+                       return DequeueTagAction.DEQUEUE;
                }
 
                return super.canDequeueTag(tag);

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/DequeueMarkupFragment.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/DequeueMarkupFragment.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/DequeueMarkupFragment.java
new file mode 100644
index 0000000..5e0a874
--- /dev/null
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/DequeueMarkupFragment.java
@@ -0,0 +1,6 @@
+package org.apache.wicket.markup.html.panel;
+
+public class DequeueMarkupFragment
+{
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java
index 676cca5..e915714 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/panel/Fragment.java
@@ -17,12 +17,10 @@
 package org.apache.wicket.markup.html.panel;
 
 import org.apache.wicket.Component;
+import org.apache.wicket.DequeueContext;
 import org.apache.wicket.IQueueRegion;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.markup.IMarkupFragment;
-import org.apache.wicket.markup.MarkupElement;
-import org.apache.wicket.markup.MarkupFragment;
-import org.apache.wicket.markup.WicketTag;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.util.lang.Args;
@@ -134,8 +132,16 @@ public class Fragment extends WebMarkupContainer 
implements IQueueRegion
                return associatedMarkupId;
        }
 
+
        @Override
-       public IMarkupFragment getDequeueMarkup() {
-               return newMarkupSourcingStrategy().getMarkup(this, null);
+       public DequeueContext newDequeueContext()
+       {
+               IMarkupFragment markup = 
newMarkupSourcingStrategy().getMarkup(this, null);
+               if (markup == null)
+               {
+                       return null;
+               }
+
+               return new DequeueContext(markup, this, true);
        }
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/2008dfb7/wicket-core/src/test/java/org/apache/wicket/queueing/ComponentQueueingTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/queueing/ComponentQueueingTest.java
 
b/wicket-core/src/test/java/org/apache/wicket/queueing/ComponentQueueingTest.java
index 96f0c77..ed76db5 100644
--- 
a/wicket-core/src/test/java/org/apache/wicket/queueing/ComponentQueueingTest.java
+++ 
b/wicket-core/src/test/java/org/apache/wicket/queueing/ComponentQueueingTest.java
@@ -18,6 +18,7 @@ package org.apache.wicket.queueing;
 
 import static org.apache.wicket.queueing.WicketMatchers.hasPath;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
 
 import java.util.ArrayList;
 
@@ -56,10 +57,8 @@ public class ComponentQueueingTest extends WicketTestCase
                MarkupContainer a = new A(), b = new B(), c = new C();
 
                p.queue(b, c, a);
-
-               tester.startPage(p);
-
                assertThat(p, hasPath(a, b, c));
+               tester.startPage(p);
        }
 
        /** {@code [a[b,c]] -> [a[b[c]]] } */
@@ -600,7 +599,7 @@ public class ComponentQueueingTest extends WicketTestCase
 
 
        @Test
-       public void nestedBorders()
+       public void border_nested()
        {
                MarkupContainer a = new A(), b = new B(), c= new C(), d = new 
D(), r = new R(), s = new S();
 
@@ -644,6 +643,23 @@ public class ComponentQueueingTest extends WicketTestCase
                assertThat(page, hasPath(new Path(fragment, r)));
                assertThat(page, hasPath(new Path(fragment, s)));
        }
+
+       @Test
+       public void fragment_doesNotDequeueAcrossRegion()
+       {
+               MarkupContainer a = new A();
+
+               TestPage page = new TestPage();
+               page.setPageMarkup("<f 
wicket:id='fragment'></f><wicket:fragment wicket:id='f'><a 
wicket:id='a'></a></wicket:fragment>");
+
+               Fragment fragment = new Fragment("fragment", "f", page);
+
+               page.queue(a, fragment);
+
+               assertThat(page, hasPath(new Path(fragment)));
+               assertThat(a.getParent(), is(nullValue()));
+       }
+
        
        @Test
        public void containerTag1()

Reply via email to