You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by da...@apache.org on 2016/11/15 08:37:28 UTC

wicket git commit: WICKET-6275 Adds stream support to MarkupContainer

Repository: wicket
Updated Branches:
  refs/heads/master 40eca5b1b -> c74869e4d


WICKET-6275 Adds stream support to MarkupContainer

Adds stream() support to MarkupContainer to enable iterating and filtering of
children. Should allow for streaming only direct children and for the whole
component tree below the markup container.

Fixes WICKET-6275


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

Branch: refs/heads/master
Commit: c74869e4dca71fcbbedf7fc300aff85abcc67391
Parents: 40eca5b
Author: Martijn Dashorst <ma...@topicus.nl>
Authored: Tue Nov 15 09:36:34 2016 +0100
Committer: Martijn Dashorst <ma...@topicus.nl>
Committed: Tue Nov 15 09:37:15 2016 +0100

----------------------------------------------------------------------
 .../java/org/apache/wicket/MarkupContainer.java | 64 ++++++++++++++++++++
 .../org/apache/wicket/MarkupContainerTest.java  | 64 ++++++++++++++++++++
 2 files changed, 128 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/c74869e4/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 6df5316..346821a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -17,13 +17,18 @@
 package org.apache.wicket;
 
 import java.io.Serializable;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Deque;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import org.apache.commons.collections4.map.LinkedMap;
 import org.apache.wicket.core.util.string.ComponentStrings;
@@ -2156,4 +2161,63 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 	{
 		add(component);
 	}
+
+	/**
+	 * Returns a sequential {@code Stream} with the direct children of this markup container as its
+	 * source. This stream doesn't traverse the component tree.
+	 *
+	 * @return a sequential {@code Stream} over the direct children of this markup container
+	 * @since 8.0
+	 */
+	public Stream<Component> stream()
+	{
+		return StreamSupport.stream(spliterator(), false);
+	}
+
+	/**
+	 * Returns a sequential {@code Stream} with the all children of this markup container as its
+	 * source. This stream does traverse the component tree.
+	 * 
+	 * @return a sequential {@code Stream} over the all children of this markup container
+	 * @since 8.0
+	 */
+	@SuppressWarnings("unchecked")
+	public Stream<Component> streamChildren()
+	{
+		class ChildrenIterator<C> implements Iterator<C>
+		{
+			private Iterator<C> currentIterator;
+
+			private Deque<Iterator<C>> iteratorStack = new ArrayDeque<>();
+
+			private ChildrenIterator(Iterator<C> iterator)
+			{
+				currentIterator = iterator;
+			}
+
+			@Override
+			public boolean hasNext()
+			{
+				if (!currentIterator.hasNext() && !iteratorStack.isEmpty())
+				{
+					currentIterator = iteratorStack.pop();
+				}
+				return currentIterator.hasNext();
+			}
+
+			@Override
+			public C next()
+			{
+				C child = currentIterator.next();
+				if (child instanceof Iterable)
+				{
+					iteratorStack.push(currentIterator);
+					currentIterator = ((Iterable<C>)child).iterator();
+				}
+				return child;
+			}
+		}
+		return StreamSupport.stream(
+			Spliterators.spliteratorUnknownSize(new ChildrenIterator<>(iterator()), 0), false);
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/c74869e4/wicket-core/src/test/java/org/apache/wicket/MarkupContainerTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/MarkupContainerTest.java b/wicket-core/src/test/java/org/apache/wicket/MarkupContainerTest.java
index aba2148..edf3f7f 100644
--- a/wicket-core/src/test/java/org/apache/wicket/MarkupContainerTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/MarkupContainerTest.java
@@ -28,6 +28,7 @@ import java.lang.reflect.Field;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 import java.util.Random;
 
 import org.apache.commons.collections4.map.LinkedMap;
@@ -37,6 +38,8 @@ import org.apache.wicket.markup.html.WebComponent;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.panel.EmptyPanel;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.StringResourceStream;
@@ -1282,4 +1285,65 @@ public class MarkupContainerTest extends WicketTestCase
 		for (int i = 0; i < numberOfChildrenToTake; i++)
 			iterator.next();
 	}
+
+	@Test
+	public void stream()
+	{
+		LoginPage loginPage = new LoginPage();
+		Optional<Component> first = loginPage.stream()
+			.filter(c -> c.getId().equals("form"))
+			.findFirst();
+		assertThat(first.isPresent(), is(false));
+
+		loginPage.add(new Form<>("form"));
+		Optional<Component> second = loginPage.stream()
+			.filter(c -> c.getId().equals("form"))
+			.findFirst();
+		assertThat(second.isPresent(), is(true));
+
+		loginPage.add(new WebMarkupContainer("wmc"));
+
+		Optional<Form> form = loginPage.stream()
+			.filter(Form.class::isInstance)
+			.map(Form.class::cast)
+			.findFirst();
+		assertThat(form.isPresent(), is(true));
+
+		Optional<WebMarkupContainer> wmc = loginPage.stream()
+			.filter(WebMarkupContainer.class::isInstance)
+			.map(WebMarkupContainer.class::cast)
+			.findFirst();
+		assertThat(wmc.isPresent(), is(true));
+	}
+
+	@Test
+	public void streamChildren()
+	{
+		LoginPage loginPage = new LoginPage();
+		Optional<Component> first = loginPage.stream()
+			.filter(c -> c.getId().equals("form"))
+			.findFirst();
+		assertThat(first.isPresent(), is(false));
+
+		Form<Object> form = new Form<>("form");
+		loginPage.add(form);
+
+		form.add(new TextField<>("field"));
+
+		assertThat(loginPage.streamChildren()
+			.filter(c -> c.getId().equals("form"))
+			.findFirst()
+			.isPresent(), is(true));
+
+		assertThat(loginPage.streamChildren()
+			.filter(c -> c.getId().equals("field"))
+			.findFirst()
+			.isPresent(), is(true));
+
+		assertThat(loginPage.streamChildren()
+			.filter(TextField.class::isInstance)
+			.filter(c -> c.getId().equals("field"))
+			.findFirst()
+			.isPresent(), is(true));
+	}
 }