You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by cm...@apache.org on 2014/09/27 21:25:00 UTC

git commit: WICKET-5677 add onReAdd to Component

Repository: wicket
Updated Branches:
  refs/heads/master 572df1583 -> 623da3924


WICKET-5677 add onReAdd to Component

Squashed commit of the following:

commit fab66e85410c14b7a0ede5c953e315a7e5143e3d
Merge: 10d83d2 c728d89
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Sat Sep 27 19:35:52 2014 +0200

    Merge branch 'wicket-6.x' into WICKET-5677

commit 10d83d2932c53dd165dbcc4c3f226f4597c142de
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Tue Aug 26 23:38:17 2014 +0200

    WICKET-5677 readd should only be called after a remove, never before

commit 0a8e964f1a3c3226f52ab22137455acf55f45c74
Merge: 055958a 3a5648b
Author: Carl-Eric Menzel <cm...@apache.org>
Date:   Mon Aug 25 07:41:06 2014 +0200

    Merge branch 'wicket-6.x' into WICKET-5677

commit 055958a9c60db45d96c1828803dbee37e5926678
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Mon Aug 25 07:23:57 2014 +0200

    add re_added flag

commit 348e9dbc899c3a62eccf7c50739162b0c0be63c2
Merge: 40c4210 c3eb7e2
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Fri Aug 22 00:29:16 2014 +0200

    Merge remote-tracking branch 'github/WICKET-5677' into WICKET-5677

    Conflicts:
    	wicket-core/src/main/java/org/apache/wicket/Component.java
    	wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java

commit c3eb7e24954d3909c74201682dba5e4de8fcadd4
Author: Carl-Eric Menzel <cm...@apache.org>
Date:   Mon Aug 18 14:08:16 2014 +0200

    WICKET-5677 clean up tests

commit 4703c1ae1af91fdcca44e34edbeeb8bbaeb63b6c
Author: Carl-Eric Menzel <cm...@apache.org>
Date:   Mon Aug 18 13:35:44 2014 +0200

    WICKET-5677 change onadd to onReAdd and only call when oninitialize wouldn't be called

commit 70b7327d2ce142707171cd31a1b612cffaa7a066
Author: Carl-Eric Menzel <cm...@apache.org>
Date:   Mon Aug 18 11:27:24 2014 +0200

    added javadoc

commit 9a6ba692a48b76c30ead6915d4bc43275a255b3c
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Mon Aug 18 10:42:33 2014 +0200

    WICKET-5677: add onAddToPage lifecycle event

commit 40c42104f9882b938dd84e8469f2922efebd2ce3
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Date:   Mon Aug 18 10:42:33 2014 +0200

    WICKET-5677: add onAddToPage lifecycle event

(cherry picked from commit 0adb864ff18951a9630bd2339fb9e92963867d4a)

Conflicts:
	wicket-core/src/main/java/org/apache/wicket/Component.java
	wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java


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

Branch: refs/heads/master
Commit: 623da39243372d2e5a93d7e2ead8c47921929d59
Parents: 572df15
Author: Carl-Eric Menzel <cm...@wicketbuch.de>
Authored: Sat Sep 27 21:24:00 2014 +0200
Committer: Carl-Eric Menzel <cm...@wicketbuch.de>
Committed: Sat Sep 27 21:24:00 2014 +0200

----------------------------------------------------------------------
 .../main/java/org/apache/wicket/Component.java  |  49 ++++-
 .../java/org/apache/wicket/MarkupContainer.java |   4 +-
 .../java/org/apache/wicket/OnReAddTest.java     | 215 +++++++++++++++++++
 3 files changed, 264 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/623da392/wicket-core/src/main/java/org/apache/wicket/Component.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java b/wicket-core/src/main/java/org/apache/wicket/Component.java
index a47d728..2b248de 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Component.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Component.java
@@ -377,8 +377,8 @@ public abstract class Component
 	protected static final int FLAG_RESERVED5 = 0x10000;
 	/** onInitialize called */
 	protected static final int FLAG_INITIALIZED = 0x20000;
-	/** Reserved subclass-definable flag bit */
-	private static final int FLAG_NOTUSED7 = 0x40000;
+	/** Set when a component is removed from the hierarchy */
+	private static final int FLAG_REMOVED = 0x40000;
 	/** Reserved subclass-definable flag bit */
 	protected static final int FLAG_RESERVED8 = 0x80000;
 
@@ -410,7 +410,7 @@ public abstract class Component
 	private static final int FLAG_VISIBILITY_ALLOWED = 0x40000000;
 
 	private static final int FLAG_DETACHING = 0x80000000;
-
+	
 	/**
 	 * The name of attribute that will hold markup id
 	 */
@@ -447,6 +447,7 @@ public abstract class Component
 	private static final short RFLAG_BEFORE_RENDER_SUPER_CALL_VERIFIED = 0x20;
 	private static final short RFLAG_INITIALIZE_SUPER_CALL_VERIFIED = 0x40;
 	protected static final short RFLAG_CONTAINER_DEQUEING = 0x80;
+	private static final short RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED = 0x100;
 
 	/**
 	 * Flags that only keep their value during the request. Useful for cache markers, etc. At the
@@ -885,6 +886,22 @@ public abstract class Component
 
 			getApplication().getComponentInitializationListeners().onInitialize(this);
 		}
+		else
+		{
+			if (getFlag(FLAG_REMOVED))
+			{
+				setFlag(FLAG_REMOVED, false);
+				setRequestFlag(RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED, false);
+				onReAdd();
+				if (!getRequestFlag(RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED))
+				{
+					throw new IllegalStateException(Component.class.getName() +
+							" has not been properly added. Something in the hierarchy of " +
+							getClass().getName() +
+							" has not called super.onReAdd() in the override of onReAdd() method");
+				}
+			}
+		}
 	}
 
 	/**
@@ -1123,6 +1140,7 @@ public abstract class Component
 	{
 		setFlag(FLAG_REMOVING_FROM_HIERARCHY, true);
 		onRemove();
+		setFlag(FLAG_REMOVED, true);
 		if (getFlag(FLAG_REMOVING_FROM_HIERARCHY))
 		{
 			throw new IllegalStateException(Component.class.getName() +
@@ -4544,4 +4562,29 @@ public abstract class Component
         	return getApplication().getPageSettings()
         		.getCallListenerInterfaceAfterExpiry() || isStateless();
 	}
+	/**
+	 * This method is called whenever a component is re-added to the page's component tree, if it
+	 * had been removed at some earlier time, i.e., if it is already initialized
+	 * (see {@link org.apache.wicket.Component#isInitialized()}).
+	 *
+	 * This is similar to onInitialize, but only comes after the component has been removed and
+	 * then
+	 * added again:
+	 *
+	 * <ul>
+	 * <li>onInitialize is only called the very first time a component is added</li>
+	 * <li>onReAdd is not called the first time, but every time it is re-added after having been
+	 * removed</li>
+	 * </ul>
+	 *
+	 * You can think of it as the opposite of onRemove. A component that was once removed will
+	 * not be
+	 * re-initialized but only re-added.
+	 *
+	 * Subclasses that override this must call super.onReAdd().
+	 */
+	protected void onReAdd()
+	{
+		setRequestFlag(RFLAG_ON_RE_ADD_SUPER_CALL_VERIFIED, true);
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/623da392/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 029fcfb..09f169c 100644
--- a/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java
@@ -970,8 +970,8 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 			{
 				child.internalInitialize();
 			}
-		}
 
+		}
 		// if the PREPARED_FOR_RENDER flag is set, we have already called
 		// beforeRender on this component's children. So we need to initialize the newly added one
 		if (isPreparedForRender())
@@ -980,6 +980,8 @@ public abstract class MarkupContainer extends Component implements Iterable<Comp
 		}
 	}
 
+
+
 	/**
 	 * THIS METHOD IS NOT PART OF THE PUBLIC API, DO NOT CALL IT
 	 * 

http://git-wip-us.apache.org/repos/asf/wicket/blob/623da392/wicket-core/src/test/java/org/apache/wicket/OnReAddTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/OnReAddTest.java b/wicket-core/src/test/java/org/apache/wicket/OnReAddTest.java
new file mode 100644
index 0000000..be664cc
--- /dev/null
+++ b/wicket-core/src/test/java/org/apache/wicket/OnReAddTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+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.util.tester.WicketTesterScope;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class OnReAddTest
+{
+	@Rule
+	public WicketTesterScope scope = new WicketTesterScope();
+
+	private boolean onReAddCalled = false;
+	private boolean onInitializeCalled = false;
+
+	@Test
+	public void onFirstAddInitializeIsCalled()
+	{
+		Page page = createPage();
+		page.internalInitialize();
+		page.add(createUninitializedProbe());
+		assertFalse(onReAddCalled);
+		assertTrue(onInitializeCalled);
+	}
+
+	@Test
+	public void nothingIsCalledWithoutConnectionToPage()
+	{
+		MarkupContainer container = createContainer();
+		container.internalInitialize();
+		container.add(createUninitializedProbe());
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+	}
+
+	@Test
+	public void uninitializedComponentIsInitializedOnConnectionToPage()
+	{
+		// "old", initialized container + "new" uninitialized component:
+		// oninitialize should be called on the component when the container
+		// is added to the page, not before.
+		MarkupContainer container = createContainer();
+		container.internalInitialize();
+		container.add(createUninitializedProbe());
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		WebPage page = createPage();
+		page.internalInitialize();
+		page.add(container);
+		assertFalse(onReAddCalled);
+		assertTrue(onInitializeCalled);
+	}
+
+	@Test
+	public void onReAddIsOnlyCalledAfterRemove()
+	{
+		Page page = createPage();
+		page.internalInitialize();
+		Component probe = createUninitializedProbe();
+		page.add(probe);
+		assertFalse(onReAddCalled);
+		assertTrue(onInitializeCalled);
+		onInitializeCalled = false;
+		page.internalInitialize();
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		page.remove(probe);
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		page.add(probe);
+		assertTrue(onReAddCalled);
+		assertFalse(onInitializeCalled);
+	}
+	
+	@Test
+	public void initializeIsCalledOnFirstAdd_OnReAddIsCalledAfterEachRemoveAndAdd()
+	{
+		Page page = createPage();
+		page.internalInitialize();
+		Component probe = createUninitializedProbe();
+		page.add(probe);
+		assertFalse(onReAddCalled);
+		assertTrue(onInitializeCalled);
+		onInitializeCalled = false;
+		page.internalInitialize();
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		page.remove(probe);
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		page.add(probe);
+		assertTrue(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		onReAddCalled = false;
+		page.internalInitialize();
+		// just another initialize run shouldn't call onReAdd nor onInitialize. onReAdd should only be called
+		// after remove and add
+		assertFalse(onReAddCalled);
+		assertFalse(onInitializeCalled);
+		page.remove(probe);
+		page.add(probe);
+		assertTrue(onReAddCalled);
+		assertFalse(onInitializeCalled);
+	}
+
+	@Test
+	public void onReAddRecursesToChildrenLikeOnInitialize()
+	{
+		Page page = createPage();
+		page.internalInitialize();
+		Component probe = createNestedProbe();
+		page.add(probe);
+		assertFalse(onReAddCalled);
+		assertTrue(onInitializeCalled);
+		onInitializeCalled = false;
+		probe.remove();
+		assertFalse(onInitializeCalled);
+		assertFalse(onReAddCalled);
+		page.add(probe);
+		assertFalse(onInitializeCalled);
+		assertTrue(onReAddCalled);
+	}
+
+	@Test
+	public void onReAddEnforcesSuperCall()
+	{
+		Page page = createPage();
+		page.internalInitialize();
+		Label brokenProbe = new Label("foo")
+		{
+			@Override
+			protected void onReAdd()
+			{
+				; // I should call super, but since I don't, this should throw an exception
+			}
+		};
+		brokenProbe.internalInitialize();
+		page.add(brokenProbe);
+		page.remove(brokenProbe);
+		try
+		{
+			page.add(brokenProbe);
+			fail("should have thrown exception");
+		} catch (IllegalStateException e)
+		{
+			assertTrue(e.getMessage().contains("super.onReAdd"));
+		}
+	}
+
+	private Component createUninitializedProbe()
+	{
+		return new Label("foo")
+		{
+			@Override
+			protected void onReAdd()
+			{
+				super.onReAdd();
+				onReAddCalled = true;
+			}
+
+			@Override
+			protected void onInitialize()
+			{
+				super.onInitialize();
+				onInitializeCalled = true;
+			}
+		};
+	}
+
+	private Component createInitializedProbe()
+	{
+		Component probe = createUninitializedProbe();
+		probe.internalInitialize();
+		return probe;
+	}
+
+	private WebPage createPage()
+	{
+		return new WebPage()
+		{
+		};
+	}
+
+	private Component createNestedProbe()
+	{
+		return createContainer().add(createUninitializedProbe());
+	}
+
+	private MarkupContainer createContainer()
+	{
+		return new WebMarkupContainer("bar");
+	}
+}