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/02/02 03:02:48 UTC

[4/4] git commit: WICKET-499 WICKET-2705 first pass at feedback storage refactoring. still some tests failing

WICKET-499 WICKET-2705 first pass at feedback storage refactoring. still some tests failing


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

Branch: refs/heads/sandbox/feedback
Commit: 27dcfc73daffc94436a5864742f4c668f20a287e
Parents: 557e435
Author: Igor Vaynberg <iv...@apache.org>
Authored: Wed Feb 1 09:31:31 2012 -0800
Committer: Igor Vaynberg <iv...@apache.org>
Committed: Wed Feb 1 09:31:31 2012 -0800

----------------------------------------------------------------------
 .../src/main/java/org/apache/wicket/Component.java |  122 ++++++++++-----
 .../src/main/java/org/apache/wicket/Session.java   |   29 ++++-
 .../DefaultCleanupFeedbackMessageFilter.java       |   35 ++++
 .../wicket/feedback/FeedbackMessageCollector.java  |   94 +++++++++++
 .../apache/wicket/feedback/FeedbackMessages.java   |  112 ++++++-------
 .../wicket/feedback/FeedbackMessagesModel.java     |    6 +-
 .../wicket/feedback/IFeedbackMessageFilter.java    |   14 ++
 .../wicket/markup/html/form/FormComponent.java     |    9 +
 .../validation/FormComponentFeedbackBorder.java    |    4 +-
 .../validation/FormComponentFeedbackIndicator.java |    5 +-
 .../apache/wicket/protocol/http/WebSession.java    |   62 --------
 .../apache/wicket/request/cycle/RequestCycle.java  |   46 +++---
 .../wicket/settings/IApplicationSettings.java      |   18 ++
 .../wicket/settings/def/ApplicationSettings.java   |   18 ++
 .../wicket/util/tester/BaseWicketTester.java       |   91 +++++++----
 .../org/apache/wicket/util/tester/FormTester.java  |    2 +-
 .../org/apache/wicket/FeedbackMessagesTest.java    |    6 +-
 .../html/form/LocalizedErrorMessageTest.java       |    4 +-
 .../markup/html/form/ValidatorPropertiesTest.java  |  112 ++++++++++----
 .../form/validation/FormValidatorBehaviorTest.java |   27 ++--
 .../innerfeedback/LocalizedFeedbackBorder.java     |   13 +-
 .../wicket/util/tester/WicketTesterTest.java       |    2 +-
 .../wicket/util/tester/apps_4/FormTesterTest.java  |   14 +-
 .../wicket/validation/ValidatorBehaviorTest.java   |   27 ++--
 .../ajax/markup/html/AjaxEditableLabel.java        |   71 +++++----
 25 files changed, 600 insertions(+), 343 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/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 e80013c..729eba9 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Component.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Component.java
@@ -36,6 +36,7 @@ import org.apache.wicket.event.IEvent;
 import org.apache.wicket.event.IEventSink;
 import org.apache.wicket.event.IEventSource;
 import org.apache.wicket.feedback.FeedbackMessage;
+import org.apache.wicket.feedback.FeedbackMessages;
 import org.apache.wicket.feedback.IFeedback;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.IMarkupFragment;
@@ -280,6 +281,13 @@ public abstract class Component
 		private static final long serialVersionUID = 1L;
 	};
 
+	/** meta data for user specified markup id */
+	private static final MetaDataKey<FeedbackMessages> FEEDBACK_KEY = new MetaDataKey<FeedbackMessages>()
+	{
+		private static final long serialVersionUID = 1L;
+	};
+
+
 	/** Basic model IModelComparator implementation for normal object models */
 	private static final IModelComparator defaultModelComparator = new IModelComparator()
 	{
@@ -1145,8 +1153,8 @@ public abstract class Component
 	 */
 	public final void debug(final Serializable message)
 	{
-		getSession().getFeedbackMessages().debug(this, message);
-		getSession().dirty();
+		getFeedbackMessages().debug(this, message);
+		addStateChange();
 	}
 
 	/**
@@ -1209,6 +1217,8 @@ public abstract class Component
 
 		requestFlags = 0;
 
+		detachFeedback();
+
 		internalDetach();
 
 		// notify any detach listener
@@ -1220,6 +1230,30 @@ public abstract class Component
 		}
 	}
 
+	private void detachFeedback()
+	{
+		FeedbackMessages feedback = getMetaData(FEEDBACK_KEY);
+		if (feedback != null)
+		{
+			final int removed = feedback.clear(getApplication().getApplicationSettings()
+				.getFeedbackMessageCleanupFilter());
+
+			if (removed != 0)
+			{
+				addStateChange();
+			}
+
+			if (feedback.isEmpty())
+			{
+				setMetaData(FEEDBACK_KEY, null);
+			}
+			else
+			{
+				feedback.detach();
+			}
+		}
+	}
+
 	/**
 	 * Removes the cached markup at the end of the request. For the next request it will be get
 	 * either from the parent's markup or from {@link MarkupCache}.
@@ -1246,20 +1280,8 @@ public abstract class Component
 	 */
 	public final void error(final Serializable message)
 	{
-		getSession().getFeedbackMessages().error(this, message);
-		getSession().dirty();
-	}
-
-	/**
-	 * Registers an fatal error feedback message for this component
-	 * 
-	 * @param message
-	 *            The feedback message
-	 */
-	public final void fatal(final Serializable message)
-	{
-		getSession().getFeedbackMessages().fatal(this, message);
-		getSession().dirty();
+		getFeedbackMessages().error(this, message);
+		addStateChange();
 	}
 
 	/**
@@ -1360,23 +1382,6 @@ public abstract class Component
 	}
 
 	/**
-	 * @return Any feedback message for this component
-	 */
-	@SuppressWarnings("deprecation")
-	public final FeedbackMessage getFeedbackMessage()
-	{
-		return getSession().getFeedbackMessages().messageForComponent(this);
-	}
-
-	/**
-	 * @return All feedback messages for this component
-	 */
-	public final List<FeedbackMessage> getFeedbackMessages()
-	{
-		return getSession().getFeedbackMessages().messagesForComponent(this);
-	}
-
-	/**
 	 * Gets the id of this component.
 	 * 
 	 * @return The id of this component
@@ -1662,7 +1667,8 @@ public abstract class Component
 			catch (Exception ex)
 			{
 				// wrap the exception so that it brings info about the component
-				RuntimeException rex = new RuntimeException("An error occurred while getting the model object for Component: " +
+				RuntimeException rex = new RuntimeException(
+					"An error occurred while getting the model object for Component: " +
 						this.toString(true), ex);
 				throw rex;
 			}
@@ -1971,19 +1977,49 @@ public abstract class Component
 	}
 
 	/**
+	 * Gets feedback messages for this component. This method will instantiate a
+	 * {@link FeedbackMessages} instance and add it to the component metadata, even when called on a
+	 * component that has no feedback messages, to avoid the overhead use
+	 * {@link #hasFeedbackMessage()}
+	 * 
+	 * @return feedback messages instance
+	 */
+	public FeedbackMessages getFeedbackMessages()
+	{
+		FeedbackMessages messages = getMetaData(FEEDBACK_KEY);
+		if (messages == null)
+		{
+			messages = new FeedbackMessages();
+			setMetaData(FEEDBACK_KEY, messages);
+		}
+		return messages;
+	}
+
+	/**
 	 * @return True if this component has an error message
 	 */
 	public final boolean hasErrorMessage()
 	{
-		return getSession().getFeedbackMessages().hasErrorMessageFor(this);
+		FeedbackMessages messages = getMetaData(FEEDBACK_KEY);
+		if (messages == null)
+		{
+			return false;
+		}
+		return messages.hasMessage(FeedbackMessage.ERROR);
 	}
 
 	/**
 	 * @return True if this component has some kind of feedback message
+	 * 
 	 */
 	public final boolean hasFeedbackMessage()
 	{
-		return getSession().getFeedbackMessages().hasMessageFor(this);
+		FeedbackMessages messages = getMetaData(FEEDBACK_KEY);
+		if (messages == null)
+		{
+			return false;
+		}
+		return messages.size() > 0;
 	}
 
 	/**
@@ -1994,8 +2030,8 @@ public abstract class Component
 	 */
 	public final void info(final Serializable message)
 	{
-		getSession().getFeedbackMessages().info(this, message);
-		getSession().dirty();
+		getFeedbackMessages().info(this, message);
+		addStateChange();
 	}
 
 	/**
@@ -2006,8 +2042,8 @@ public abstract class Component
 	 */
 	public final void success(final Serializable message)
 	{
-		getSession().getFeedbackMessages().success(this, message);
-		getSession().dirty();
+		getFeedbackMessages().success(this, message);
+		addStateChange();
 	}
 
 	/**
@@ -3441,8 +3477,8 @@ public abstract class Component
 	 */
 	public final void warn(final Serializable message)
 	{
-		getSession().getFeedbackMessages().warn(this, message);
-		getSession().dirty();
+		getFeedbackMessages().warn(this, message);
+		addStateChange();
 	}
 
 	/**
@@ -3922,7 +3958,7 @@ public abstract class Component
 			// Apply behavior modifiers
 			List<? extends Behavior> behaviors = getBehaviors();
 			if ((behaviors != null) && !behaviors.isEmpty() && !tag.isClose() &&
-					(isIgnoreAttributeModifier() == false))
+				(isIgnoreAttributeModifier() == false))
 			{
 				tag = tag.mutable();
 				for (Behavior behavior : behaviors)

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/Session.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/Session.java b/wicket-core/src/main/java/org/apache/wicket/Session.java
index 24258b1..efcb7e8 100644
--- a/wicket-core/src/main/java/org/apache/wicket/Session.java
+++ b/wicket-core/src/main/java/org/apache/wicket/Session.java
@@ -36,10 +36,12 @@ import org.apache.wicket.request.ClientInfo;
 import org.apache.wicket.request.Request;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.session.ISessionStore;
+import org.apache.wicket.settings.IApplicationSettings;
 import org.apache.wicket.util.IProvider;
 import org.apache.wicket.util.LazyInitializer;
 import org.apache.wicket.util.lang.Objects;
 import org.apache.wicket.util.lang.WicketObjects;
+import org.apache.wicket.util.tester.BaseWicketTester;
 import org.apache.wicket.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -268,8 +270,16 @@ public abstract class Session implements IClusterable, IEventSink
 	/**
 	 * Cleans up all rendered feedback messages and any unrendered, dangling feedback messages there
 	 * may be left after that.
+	 * 
+	 * @deprecated see
+	 *             {@link IApplicationSettings#setFeedbackMessageCleanupFilter(org.apache.wicket.feedback.IFeedbackMessageFilter)}
+	 *             for cleanup during testing see {@link BaseWicketTester#cleanupFeedbackMessages()}
 	 */
-	public abstract void cleanupFeedbackMessages();
+	@Deprecated
+	public final void cleanupFeedbackMessages2()
+	{
+		throw new UnsupportedOperationException("Deprecated, see the javadoc");
+	}
 
 
 	/**
@@ -640,12 +650,27 @@ public abstract class Session implements IClusterable, IEventSink
 	 */
 	public void detach()
 	{
+		detachFeedback();
+
 		if (sessionInvalidated)
 		{
 			invalidateNow();
 		}
 	}
 
+	private void detachFeedback()
+	{
+		final int removed = feedbackMessages.clear(getApplication().getApplicationSettings()
+			.getFeedbackMessageCleanupFilter());
+
+		if (removed != 0)
+		{
+			dirty();
+		}
+
+		feedbackMessages.detach();
+	}
+
 	/**
 	 * NOT PART OF PUBLIC API, DO NOT CALL
 	 * 
@@ -838,7 +863,7 @@ public abstract class Session implements IClusterable, IEventSink
 
 	/**
 	 * Returns the {@link IPageManager} instance.
-	 *
+	 * 
 	 * @return {@link IPageManager} instance.
 	 */
 	public final IPageManager getPageManager()

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/feedback/DefaultCleanupFeedbackMessageFilter.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/feedback/DefaultCleanupFeedbackMessageFilter.java b/wicket-core/src/main/java/org/apache/wicket/feedback/DefaultCleanupFeedbackMessageFilter.java
new file mode 100755
index 0000000..b536d06
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/feedback/DefaultCleanupFeedbackMessageFilter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.feedback;
+
+/**
+ * The default message filter used to cleanup feedback messages. This message accepts (and therefore
+ * removes) all rendered feedback messages.
+ * 
+ * @author igor
+ */
+public class DefaultCleanupFeedbackMessageFilter implements IFeedbackMessageFilter
+{
+	private static final long serialVersionUID = 1L;
+
+	@Override
+	public boolean accept(FeedbackMessage message)
+	{
+		return message.isRendered();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessageCollector.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessageCollector.java b/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessageCollector.java
new file mode 100755
index 0000000..08028b6
--- /dev/null
+++ b/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessageCollector.java
@@ -0,0 +1,94 @@
+/*
+ * 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.feedback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.util.visit.IVisit;
+import org.apache.wicket.util.visit.IVisitor;
+
+/**
+ * Collects feedback messages from all the places where they can be stored.
+ * 
+ * @author igor
+ */
+public final class FeedbackMessageCollector
+{
+	private final Component root;
+	private boolean includeSession = true;
+	private boolean recursive = true;
+
+	public FeedbackMessageCollector(Component root)
+	{
+		this.root = root;
+	}
+
+	public FeedbackMessageCollector setIncludeSession(boolean value)
+	{
+		includeSession = value;
+		return this;
+	}
+
+	public FeedbackMessageCollector setRecursive(boolean value)
+	{
+		recursive = value;
+		return this;
+	}
+
+	public List<FeedbackMessage> collect()
+	{
+		return collect(IFeedbackMessageFilter.ALL);
+	}
+
+	public List<FeedbackMessage> collect(final IFeedbackMessageFilter filter)
+	{
+		final List<FeedbackMessage> messages = new ArrayList<FeedbackMessage>();
+
+		if (includeSession)
+		{
+			messages.addAll(root.getSession().getFeedbackMessages().messages(filter));
+		}
+
+		if (root.hasFeedbackMessage())
+		{
+			messages.addAll(root.getFeedbackMessages().messages(filter));
+		}
+
+		if (recursive && root instanceof MarkupContainer)
+		{
+			((MarkupContainer)root).visitChildren(new IVisitor<Component, Void>()
+			{
+
+				@Override
+				public void component(Component object, IVisit<Void> visit)
+				{
+					if (object.hasFeedbackMessage())
+					{
+						messages.addAll(object.getFeedbackMessages().messages(filter));
+					}
+				}
+			});
+		}
+
+		return messages;
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessages.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessages.java b/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessages.java
index 39bca6c..bb593f7 100644
--- a/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessages.java
+++ b/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessages.java
@@ -25,12 +25,10 @@ import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.IClusterable;
-import org.apache.wicket.util.lang.Objects;
 import org.apache.wicket.util.string.StringList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 /**
  * Holds list of feedback messages. The list can be added to, cleared, queried and filtered.
  * <p>
@@ -74,7 +72,7 @@ public final class FeedbackMessages implements IClusterable, Iterable<FeedbackMe
 		}
 		messages.add(message);
 	}
-	
+
 	/**
 	 * Adds a message
 	 * 
@@ -220,50 +218,53 @@ public final class FeedbackMessages implements IClusterable, Iterable<FeedbackMe
 	}
 
 	/**
-	 * Looks up whether the given component registered a message with this list.
+	 * Checks if a message of the specified {@code level} was registered
 	 * 
-	 * @param component
-	 *            the component to look up whether it registered a message
-	 * @return whether the given component registered a message with this list
+	 * @param level
+	 *            The level of the message
+	 * @return {code true} iff a message with the specified {@code level} was registered
 	 */
-	public final boolean hasMessageFor(Component component)
+	public final boolean hasMessage(final int level)
 	{
-		return hasMessage(new ComponentFeedbackMessageFilter(component));
+		for (FeedbackMessage message : messages)
+		{
+			if (message.isLevel(level))
+			{
+				return true;
+			}
+		}
+		return false;
 	}
 
 	/**
-	 * Looks up whether the given component registered a message with this list with the given
-	 * level.
+	 * Retrieves the first message
 	 * 
-	 * @param component
-	 *            The component to look up whether it registered a message
 	 * @param level
 	 *            The level of the message
-	 * @return Whether the given component registered a message with this list with the given level
+	 * @return message or {@code null} if none
 	 */
-	public final boolean hasMessageFor(final Component component, final int level)
+	public final FeedbackMessage first()
 	{
-		return hasMessage(new IFeedbackMessageFilter()
-		{
-			@Override
-			public boolean accept(FeedbackMessage message)
-			{
-				return Objects.equal(message.getReporter(), component) && message.isLevel(level);
-			}
-		});
+		return messages.size() > 0 ? messages.get(0) : null;
 	}
 
 	/**
-	 * Convenience method that looks up whether the given component registered a message with this
-	 * list with the level ERROR.
+	 * Retrieves the first message matching the specified {@code level}
 	 * 
-	 * @param component
-	 *            the component to look up whether it registered a message
-	 * @return whether the given component registered a message with this list with level ERROR
+	 * @param level
+	 *            The level of the message
+	 * @return matching message or {@code null} if none
 	 */
-	public final boolean hasErrorMessageFor(Component component)
+	public final FeedbackMessage first(final int level)
 	{
-		return hasMessageFor(component, FeedbackMessage.ERROR);
+		for (FeedbackMessage message : messages)
+		{
+			if (message.isLevel(level))
+			{
+				return message;
+			}
+		}
+		return null;
 	}
 
 	/**
@@ -303,36 +304,6 @@ public final class FeedbackMessages implements IClusterable, Iterable<FeedbackMe
 	}
 
 	/**
-	 * Looks up a single message for the given component.
-	 * 
-	 * @param component
-	 *            the component to look up the message for
-	 * @return the message that is found for the given component (first match) or null if none was
-	 *         found
-	 *         
-	 * @deprecated use {@link FeedbackMessages#messagesForComponent(org.apache.wicket.Component)} instead
-	 */
-	@Deprecated
-	public final FeedbackMessage messageForComponent(final Component component)
-	{
-		final List<FeedbackMessage> list = messagesForComponent(component);
-
-		return list.isEmpty() ? null : list.get(0);
-	}
-
-	/**
-	 * Looks up the messages for the given component.
-	 * 
-	 * @param component
-	 *            the component to look up the message for
-	 * @return the messages that were found for the given component
-	 */
-	public final List<FeedbackMessage> messagesForComponent(final Component component)
-	{
-		return messages(new ComponentFeedbackMessageFilter(component)); 
-	}
-
-	/**
 	 * Gets whether there are no messages.
 	 * 
 	 * @return True when there are no messages
@@ -381,4 +352,25 @@ public final class FeedbackMessages implements IClusterable, Iterable<FeedbackMe
 	{
 		return "[feedbackMessages = " + StringList.valueOf(messages) + ']';
 	}
+
+	/**
+	 * Retrieves all stored messages as an unmodifiable list
+	 * 
+	 * @return stored messages as unmodifiable list
+	 */
+	public List<FeedbackMessage> toList()
+	{
+		return Collections.unmodifiableList(messages);
+	}
+
+	/**
+	 * Detaches each stored message
+	 */
+	public void detach()
+	{
+		for (FeedbackMessage message : messages)
+		{
+			message.detach();
+		}
+	}
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessagesModel.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessagesModel.java b/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessagesModel.java
index 2feed2b..8d10804 100644
--- a/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessagesModel.java
+++ b/wicket-core/src/main/java/org/apache/wicket/feedback/FeedbackMessagesModel.java
@@ -23,7 +23,6 @@ import java.util.List;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.Page;
-import org.apache.wicket.Session;
 import org.apache.wicket.model.IModel;
 
 
@@ -45,6 +44,8 @@ public class FeedbackMessagesModel implements IModel<List<FeedbackMessage>>
 	/** Comparator used for sorting the messages. */
 	private Comparator<FeedbackMessage> sortingComparator;
 
+	private final Component component;
+
 	/**
 	 * Constructor. Creates a model for all feedback messages on the page.
 	 * 
@@ -58,6 +59,7 @@ public class FeedbackMessagesModel implements IModel<List<FeedbackMessage>>
 		{
 			throw new IllegalArgumentException("Argument 'component' cannot be null");
 		}
+		this.component = component;
 	}
 
 	/**
@@ -101,7 +103,7 @@ public class FeedbackMessagesModel implements IModel<List<FeedbackMessage>>
 		if (messages == null)
 		{
 			// Get filtered messages from page where component lives
-			messages = Session.get().getFeedbackMessages().messages(filter);
+			messages = new FeedbackMessageCollector(component).collect(filter);
 
 			// Sort the list before returning it
 			if (sortingComparator != null)

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/feedback/IFeedbackMessageFilter.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/feedback/IFeedbackMessageFilter.java b/wicket-core/src/main/java/org/apache/wicket/feedback/IFeedbackMessageFilter.java
index 1dbfbbf..9372511 100644
--- a/wicket-core/src/main/java/org/apache/wicket/feedback/IFeedbackMessageFilter.java
+++ b/wicket-core/src/main/java/org/apache/wicket/feedback/IFeedbackMessageFilter.java
@@ -40,6 +40,20 @@ public interface IFeedbackMessageFilter extends IClusterable
 	};
 
 	/**
+	 * Filter that does not match any message
+	 */
+	public static final IFeedbackMessageFilter NONE = new IFeedbackMessageFilter()
+	{
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		public boolean accept(FeedbackMessage message)
+		{
+			return false;
+		}
+	};
+
+	/**
 	 * @param message
 	 *            The message to test for inclusion
 	 * @return True if the message should be included, false to exclude it

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
index ec7b2f9..7db574a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java
@@ -1087,6 +1087,15 @@ public abstract class FormComponent<T> extends LabeledWebMarkupContainer
 	 */
 	public void validate()
 	{
+		// clear any previous feedback messages
+
+		if (hasFeedbackMessage())
+		{
+			getFeedbackMessages().clear();
+		}
+
+		// validate
+
 		validateRequired();
 		if (isValid())
 		{

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackBorder.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackBorder.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackBorder.java
index dfc4e3f..6fbab57 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackBorder.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackBorder.java
@@ -16,8 +16,8 @@
  */
 package org.apache.wicket.markup.html.form.validation;
 
-import org.apache.wicket.Session;
 import org.apache.wicket.feedback.ContainerFeedbackMessageFilter;
+import org.apache.wicket.feedback.FeedbackMessageCollector;
 import org.apache.wicket.feedback.IFeedback;
 import org.apache.wicket.feedback.IFeedbackMessageFilter;
 import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -91,7 +91,7 @@ public class FormComponentFeedbackBorder extends Border implements IFeedback
 	{
 		super.onBeforeRender();
 		// Get the messages for the current page
-		visible = Session.get().getFeedbackMessages().messages(getMessagesFilter()).size() != 0;
+		visible = new FeedbackMessageCollector(getPage()).collect(getMessagesFilter()).size() > 0;
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackIndicator.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackIndicator.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackIndicator.java
index 7498720..5926b54 100644
--- a/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackIndicator.java
+++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/form/validation/FormComponentFeedbackIndicator.java
@@ -17,8 +17,8 @@
 package org.apache.wicket.markup.html.form.validation;
 
 import org.apache.wicket.Component;
-import org.apache.wicket.Session;
 import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
+import org.apache.wicket.feedback.FeedbackMessageCollector;
 import org.apache.wicket.feedback.IFeedback;
 import org.apache.wicket.feedback.IFeedbackMessageFilter;
 import org.apache.wicket.markup.html.panel.Panel;
@@ -67,7 +67,8 @@ public class FormComponentFeedbackIndicator extends Panel implements IFeedback
 	{
 		super.onConfigure();
 		// Get the messages for the current page
-		setVisible(Session.get().getFeedbackMessages().hasMessage(getFeedbackMessageFilter()));
+		setVisible(new FeedbackMessageCollector(getPage()).collect(getFeedbackMessageFilter())
+			.size() > 0);
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebSession.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebSession.java b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebSession.java
index 514c651..1770c67 100644
--- a/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebSession.java
+++ b/wicket-core/src/main/java/org/apache/wicket/protocol/http/WebSession.java
@@ -16,9 +16,6 @@
  */
 package org.apache.wicket.protocol.http;
 
-import java.util.List;
-
-import org.apache.wicket.Application;
 import org.apache.wicket.MetaDataKey;
 import org.apache.wicket.RestartResponseAtInterceptPageException;
 import org.apache.wicket.Session;
@@ -30,9 +27,6 @@ import org.apache.wicket.markup.html.pages.BrowserInfoPage;
 import org.apache.wicket.protocol.http.request.WebClientInfo;
 import org.apache.wicket.request.Request;
 import org.apache.wicket.request.cycle.RequestCycle;
-import org.apache.wicket.request.http.WebRequest;
-import org.apache.wicket.request.http.WebResponse;
-import org.apache.wicket.settings.IRequestCycleSettings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -98,62 +92,6 @@ public class WebSession extends Session
 		super(request);
 	}
 
-
-	/**
-	 * @see org.apache.wicket.Session#cleanupFeedbackMessages()
-	 */
-	@Override
-	public void cleanupFeedbackMessages()
-	{
-		// remove all component feedback messages if we are either using one
-		// pass or render to buffer render strategy (in which case we can remove
-		// without further delay) or in case the redirect to render strategy is
-		// used, when we're doing the render request (isRedirect should return
-		// false in that case)
-
-		// TODO NG - does this huge if really make sense?
-
-		if (Application.get().getRequestCycleSettings().getRenderStrategy() != IRequestCycleSettings.RenderStrategy.REDIRECT_TO_RENDER ||
-			((WebRequest)RequestCycle.get().getRequest()).isAjax() ||
-			(!((WebResponse)RequestCycle.get().getResponse()).isRedirect()))
-		{
-			// If session scoped, rendered messages got indeed cleaned up, mark
-			// the session as dirty
-			if (getFeedbackMessages().clear(RENDERED_SESSION_SCOPED_MESSAGES) > 0)
-			{
-				dirty();
-			}
-
-			// see if any component related feedback messages were left unrendered and warn if in
-			// dev mode
-			if (getApplication().usesDevelopmentConfig())
-			{
-				List<FeedbackMessage> messages = getFeedbackMessages().messages(
-					WebSession.MESSAGES_FOR_COMPONENTS);
-				for (FeedbackMessage message : messages)
-				{
-					if (!message.isRendered())
-					{
-						logger.warn(
-							"Component-targetted feedback message was left unrendered. This could be because you are missing a FeedbackPanel on the page.  Message: {}",
-							message);
-					}
-				}
-			}
-
-			cleanupComponentFeedbackMessages();
-		}
-	}
-
-	/**
-	 * Clear all feedback messages
-	 */
-	protected void cleanupComponentFeedbackMessages()
-	{
-		// clean up all component related feedback messages
-		getFeedbackMessages().clear(WebSession.MESSAGES_FOR_COMPONENTS);
-	}
-
 	/**
 	 * Call signOut() and remove the logon data from whereever they have been persisted (e.g.
 	 * Cookies)

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java b/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java
index 32103aa..06e16c8 100644
--- a/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java
+++ b/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java
@@ -45,6 +45,7 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.resource.IResource;
 import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.request.resource.caching.IStaticCacheableResource;
+import org.apache.wicket.settings.IApplicationSettings;
 import org.apache.wicket.util.lang.Args;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,8 +70,6 @@ public class RequestCycle implements IRequestCycle, IEventSink
 {
 	private static final Logger log = LoggerFactory.getLogger(RequestCycle.class);
 
-	private boolean cleanupFeedbackMessagesOnDetach;
-
 	/**
 	 * Returns request cycle associated with current thread.
 	 * 
@@ -126,7 +125,6 @@ public class RequestCycle implements IRequestCycle, IEventSink
 		Args.notNull(context.getRequestMapper(), "context.requestMapper");
 		Args.notNull(context.getExceptionMapper(), "context.exceptionMapper");
 
-		cleanupFeedbackMessagesOnDetach = true;
 		listeners = new RequestCycleListenerCollection();
 		startTime = System.currentTimeMillis();
 		requestHandlerExecutor = new HandlerExecutor();
@@ -453,7 +451,8 @@ public class RequestCycle implements IRequestCycle, IEventSink
 	 */
 	public final CharSequence urlFor(ResourceReference reference, PageParameters params)
 	{
-		ResourceReferenceRequestHandler handler = new ResourceReferenceRequestHandler(reference, params);
+		ResourceReferenceRequestHandler handler = new ResourceReferenceRequestHandler(reference,
+			params);
 		return renderUrl(mapUrlFor(handler), handler);
 	}
 
@@ -474,7 +473,7 @@ public class RequestCycle implements IRequestCycle, IEventSink
 		final PageParameters parameters)
 	{
 		IRequestHandler handler = new BookmarkablePageRequestHandler(new PageProvider(pageClass,
-				parameters));
+			parameters));
 		return renderUrl(mapUrlFor(handler), handler);
 	}
 
@@ -501,7 +500,7 @@ public class RequestCycle implements IRequestCycle, IEventSink
 			String renderedUrl = getUrlRenderer().renderUrl(url);
 			if (handler instanceof ResourceReferenceRequestHandler)
 			{
-				ResourceReferenceRequestHandler rrrh = (ResourceReferenceRequestHandler) handler;
+				ResourceReferenceRequestHandler rrrh = (ResourceReferenceRequestHandler)handler;
 				IResource resource = rrrh.getResource();
 				if (resource instanceof IStaticCacheableResource == false)
 				{
@@ -510,7 +509,7 @@ public class RequestCycle implements IRequestCycle, IEventSink
 			}
 			else if (handler instanceof ResourceRequestHandler)
 			{
-				ResourceRequestHandler rrh = (ResourceRequestHandler) handler;
+				ResourceRequestHandler rrh = (ResourceRequestHandler)handler;
 				IResource resource = rrh.getResource();
 				if (resource instanceof IStaticCacheableResource == false)
 				{
@@ -572,14 +571,6 @@ public class RequestCycle implements IRequestCycle, IEventSink
 	 */
 	public void onDetach()
 	{
-		if (cleanupFeedbackMessagesOnDetach)
-		{
-			if (Session.exists())
-			{
-				Session.get().cleanupFeedbackMessages();
-			}
-		}
-
 		try
 		{
 			onEndRequest();
@@ -653,10 +644,14 @@ public class RequestCycle implements IRequestCycle, IEventSink
 	 * Gets whether or not feedback messages are to be cleaned up on detach.
 	 * 
 	 * @return true if they are
+	 * @deprecated see {@link IApplicationSettings#getFeedbackMessageCleanupFilter()}
+	 * 
+	 *             TODO 7.0 remove
 	 */
-	public boolean isCleanupFeedbackMessagesOnDetach()
+	@Deprecated
+	public final boolean isCleanupFeedbackMessagesOnDetach()
 	{
-		return cleanupFeedbackMessagesOnDetach;
+		throw new UnsupportedOperationException("Deprecated, see javadoc");
 	}
 
 	/**
@@ -664,10 +659,15 @@ public class RequestCycle implements IRequestCycle, IEventSink
 	 * 
 	 * @param cleanupFeedbackMessagesOnDetach
 	 *            true if you want them to be cleaned up
+	 * 
+	 * @deprecated see {@link #isCleanupFeedbackMessagesOnDetach()}
+	 * 
+	 *             TODO 7.0 remove
 	 */
-	public void setCleanupFeedbackMessagesOnDetach(boolean cleanupFeedbackMessagesOnDetach)
+	@Deprecated
+	public final void setCleanupFeedbackMessagesOnDetach(boolean cleanupFeedbackMessagesOnDetach)
 	{
-		this.cleanupFeedbackMessagesOnDetach = cleanupFeedbackMessagesOnDetach;
+		throw new UnsupportedOperationException("Deprecated, see javadoc");
 	}
 
 	/**
@@ -768,9 +768,9 @@ public class RequestCycle implements IRequestCycle, IEventSink
 	}
 
 	/**
-	 * Finds a IRequestHandler which is either the currently executing handler or
-	 * is scheduled to be executed.
-	 *
+	 * Finds a IRequestHandler which is either the currently executing handler or is scheduled to be
+	 * executed.
+	 * 
 	 * @return the found IRequestHandler or {@code null}
 	 */
 	public <T extends IRequestHandler> T find(final Class<T> type)
@@ -791,7 +791,7 @@ public class RequestCycle implements IRequestCycle, IEventSink
 			}
 		}
 
-		return (T) result;
+		return (T)result;
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/settings/IApplicationSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/IApplicationSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/IApplicationSettings.java
index 3d85ddc..eabcb77 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/IApplicationSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/IApplicationSettings.java
@@ -18,6 +18,7 @@ package org.apache.wicket.settings;
 
 import org.apache.wicket.Page;
 import org.apache.wicket.application.IClassResolver;
+import org.apache.wicket.feedback.IFeedbackMessageFilter;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.util.lang.Bytes;
 
@@ -132,4 +133,21 @@ public interface IApplicationSettings
 	 *            if true upload progress monitoring is enabled
 	 */
 	void setUploadProgressUpdatesEnabled(boolean uploadProgressUpdatesEnabled);
+
+	/**
+	 * Sets the cleanup feedback message filter. see {@link #getFeedbackMessageCleanupFilter()} for
+	 * more details.
+	 * 
+	 * @param filter
+	 */
+	void setFeedbackMessageCleanupFilter(IFeedbackMessageFilter filter);
+
+	/**
+	 * Returns the cleanup feedack message filter. At the end of request all messages are ran
+	 * through this filter, and the ones accepted are removed. The default implementation accepts
+	 * (and therefore remkoves) all rendered messages.
+	 * 
+	 * @return feedback message filter
+	 */
+	IFeedbackMessageFilter getFeedbackMessageCleanupFilter();
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/settings/def/ApplicationSettings.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/def/ApplicationSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/def/ApplicationSettings.java
index 99fd532..4720df9 100644
--- a/wicket-core/src/main/java/org/apache/wicket/settings/def/ApplicationSettings.java
+++ b/wicket-core/src/main/java/org/apache/wicket/settings/def/ApplicationSettings.java
@@ -21,7 +21,10 @@ import java.lang.ref.WeakReference;
 import org.apache.wicket.Page;
 import org.apache.wicket.application.DefaultClassResolver;
 import org.apache.wicket.application.IClassResolver;
+import org.apache.wicket.feedback.DefaultCleanupFeedbackMessageFilter;
+import org.apache.wicket.feedback.IFeedbackMessageFilter;
 import org.apache.wicket.settings.IApplicationSettings;
+import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Bytes;
 
 /**
@@ -49,6 +52,8 @@ public class ApplicationSettings implements IApplicationSettings
 
 	private boolean uploadProgressUpdatesEnabled = false;
 
+	private IFeedbackMessageFilter feedbackMessageCleanupFilter = new DefaultCleanupFeedbackMessageFilter();
+
 	/**
 	 * @see org.apache.wicket.settings.IApplicationSettings#getAccessDeniedPage()
 	 */
@@ -192,4 +197,17 @@ public class ApplicationSettings implements IApplicationSettings
 				" must be a subclass of Page");
 		}
 	}
+
+	@Override
+	public void setFeedbackMessageCleanupFilter(IFeedbackMessageFilter filter)
+	{
+		Args.notNull(filter, "filter");
+		feedbackMessageCleanupFilter = filter;
+	}
+
+	@Override
+	public IFeedbackMessageFilter getFeedbackMessageCleanupFilter()
+	{
+		return feedbackMessageCleanupFilter;
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java b/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
index 1ace0d4..77a5c45 100644
--- a/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
+++ b/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java
@@ -64,8 +64,9 @@ import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
 import org.apache.wicket.behavior.AbstractAjaxBehavior;
 import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.feedback.ErrorLevelFeedbackMessageFilter;
 import org.apache.wicket.feedback.FeedbackMessage;
-import org.apache.wicket.feedback.FeedbackMessages;
+import org.apache.wicket.feedback.FeedbackMessageCollector;
 import org.apache.wicket.feedback.IFeedbackMessageFilter;
 import org.apache.wicket.markup.ContainerInfo;
 import org.apache.wicket.markup.IMarkupFragment;
@@ -83,7 +84,6 @@ import org.apache.wicket.markup.html.link.BookmarkablePageLink;
 import org.apache.wicket.markup.html.link.ILinkListener;
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.markup.html.list.ListView;
-import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.markup.parser.XmlPullParser;
 import org.apache.wicket.markup.parser.XmlTag;
 import org.apache.wicket.mock.MockApplication;
@@ -188,6 +188,8 @@ public class BaseWicketTester
 
 	private IRequestHandler forcedHandler;
 
+	private IFeedbackMessageFilter originalFeedbackMessageCleanupFilter;
+
 	// Simulates the cookies maintained by the browser
 	private final List<Cookie> browserCookies = Generics.newArrayList();
 
@@ -301,6 +303,12 @@ public class BaseWicketTester
 		application.setRequestCycleProvider(new TestRequestCycleProvider(
 			application.getRequestCycleProvider()));
 
+		// set a feedback message filter that will not remove any messages
+		originalFeedbackMessageCleanupFilter = application.getApplicationSettings()
+			.getFeedbackMessageCleanupFilter();
+		application.getApplicationSettings().setFeedbackMessageCleanupFilter(
+			IFeedbackMessageFilter.NONE);
+
 		IPageManagerProvider pageManagerProvider = newTestPageManagerProvider();
 		if (pageManagerProvider != null)
 		{
@@ -376,7 +384,6 @@ public class BaseWicketTester
 		ServletWebRequest servletWebRequest = newServletWebRequest();
 		requestCycle = application.createRequestCycle(servletWebRequest,
 			newServletWebResponse(servletWebRequest));
-		requestCycle.setCleanupFeedbackMessagesOnDetach(false);
 		ThreadContext.setRequestCycle(requestCycle);
 
 		if (session == null)
@@ -386,6 +393,38 @@ public class BaseWicketTester
 	}
 
 	/**
+	 * Cleans up feedback messages. This usually happens on detach, but is disabled in unit testing
+	 * so feedback mesasges can be examined.
+	 */
+	public void cleanupFeedbackMessages()
+	{
+		cleanupFeedbackMessages(originalFeedbackMessageCleanupFilter);
+	}
+
+	/**
+	 * Removes all feedback messages
+	 */
+	public void clearFeedbackMessages()
+	{
+		cleanupFeedbackMessages(IFeedbackMessageFilter.ALL);
+	}
+
+	/**
+	 * Cleans up feedback messages given the specified filter.
+	 * 
+	 * @param filter
+	 *            filter used to cleanup messages, accepted messages will be removed
+	 */
+	private void cleanupFeedbackMessages(IFeedbackMessageFilter filter)
+	{
+		application.getApplicationSettings().setFeedbackMessageCleanupFilter(filter);
+		getLastRenderedPage().detach();
+		getSession().detach();
+		application.getApplicationSettings().setFeedbackMessageCleanupFilter(
+			IFeedbackMessageFilter.NONE);
+	}
+
+	/**
 	 * Copies all cookies with a positive age from the last response to the request that is going to
 	 * be used for the next cycle.
 	 */
@@ -592,15 +631,6 @@ public class BaseWicketTester
 
 		try
 		{
-			if (!redirect)
-			{
-				/*
-				 * we do not reset the session during redirect processing because we want to
-				 * preserve the state before the redirect, eg any error messages reported
-				 */
-				session.cleanupFeedbackMessages();
-			}
-
 			if (getLastResponse() != null)
 			{
 				// transfer cookies from previous response to this request, quirky but how old stuff
@@ -1111,7 +1141,7 @@ public class BaseWicketTester
 
 		// prepare the request
 		request.setUrl(application.getRootRequestMapper().mapHandler(
-				new BookmarkablePageRequestHandler(new PageProvider(pageClass, parameters))));
+			new BookmarkablePageRequestHandler(new PageProvider(pageClass, parameters))));
 
 		// process the request
 		processRequest();
@@ -1198,7 +1228,8 @@ public class BaseWicketTester
 		catch (Exception e)
 		{
 			log.error(e.getMessage(), e);
-			fail(String.format("Cannot instantiate component with type '%s' because of '%s'", componentClass.getName(), e.getMessage()));
+			fail(String.format("Cannot instantiate component with type '%s' because of '%s'",
+				componentClass.getName(), e.getMessage()));
 		}
 
 		// process the component
@@ -1615,7 +1646,7 @@ public class BaseWicketTester
 	public Result ifContains(String pattern)
 	{
 		return isTrue("pattern '" + pattern + "' not found in:\n" + getLastResponseAsString(),
-				getLastResponseAsString().matches("(?s).*" + pattern + ".*"));
+			getLastResponseAsString().matches("(?s).*" + pattern + ".*"));
 	}
 
 	/**
@@ -1628,7 +1659,7 @@ public class BaseWicketTester
 	public Result ifContainsNot(String pattern)
 	{
 		return isFalse("pattern '" + pattern + "' found",
-				getLastResponseAsString().matches("(?s).*" + pattern + ".*"));
+			getLastResponseAsString().matches("(?s).*" + pattern + ".*"));
 	}
 
 	/**
@@ -1898,8 +1929,8 @@ public class BaseWicketTester
 	{
 		List<Serializable> messages = getMessages(FeedbackMessage.ERROR);
 		return isTrue(
-				"expect no error message, but contains\n" + WicketTesterHelper.asLined(messages),
-				messages.isEmpty());
+			"expect no error message, but contains\n" + WicketTesterHelper.asLined(messages),
+			messages.isEmpty());
 	}
 
 	/**
@@ -1926,18 +1957,9 @@ public class BaseWicketTester
 	 */
 	public List<Serializable> getMessages(final int level)
 	{
-		FeedbackMessages feedbackMessages = Session.get().getFeedbackMessages();
-		List<FeedbackMessage> allMessages = feedbackMessages.messages(new IFeedbackMessageFilter()
-		{
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public boolean accept(FeedbackMessage message)
-			{
-				return message.getLevel() == level;
-			}
-		});
 
+		List<FeedbackMessage> allMessages = new FeedbackMessageCollector(getLastRenderedPage()).collect(new ErrorLevelFeedbackMessageFilter(
+			level));
 		List<Serializable> actualMessages = Generics.newArrayList();
 		for (FeedbackMessage message : allMessages)
 		{
@@ -1983,8 +2005,9 @@ public class BaseWicketTester
 
 	/**
 	 * Tests that a <code>Component</code> has been added to a <code>AjaxRequestTarget</code>, using
-	 * {@link org.apache.wicket.ajax.AjaxRequestTarget#add(org.apache.wicket.Component...)}. This method actually tests that a
-	 * <code>Component</code> is on the Ajax response sent back to the client.
+	 * {@link org.apache.wicket.ajax.AjaxRequestTarget#add(org.apache.wicket.Component...)}. This
+	 * method actually tests that a <code>Component</code> is on the Ajax response sent back to the
+	 * client.
 	 * <p>
 	 * PLEASE NOTE! This method doesn't actually insert the <code>Component</code> in the client DOM
 	 * tree, using JavaScript. But it shouldn't be needed because you have to trust that the Wicket
@@ -2067,7 +2090,7 @@ public class BaseWicketTester
 
 	/**
 	 * Simulates the firing of all ajax timer behaviors on the page
-	 *
+	 * 
 	 * @param container
 	 */
 	public void executeAllTimerBehaviors(final MarkupContainer container)
@@ -2085,8 +2108,8 @@ public class BaseWicketTester
 					checkUsability(component, true);
 
 					log.debug("Triggering AjaxSelfUpdatingTimerBehavior: " +
-							component.getClassRelativePath());
-					AbstractAjaxTimerBehavior timer = (AbstractAjaxTimerBehavior) b;
+						component.getClassRelativePath());
+					AbstractAjaxTimerBehavior timer = (AbstractAjaxTimerBehavior)b;
 					if (!timer.isStopped())
 					{
 						executeBehavior(timer);

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/main/java/org/apache/wicket/util/tester/FormTester.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/util/tester/FormTester.java b/wicket-core/src/main/java/org/apache/wicket/util/tester/FormTester.java
index 86f9fbf..421fefb 100644
--- a/wicket-core/src/main/java/org/apache/wicket/util/tester/FormTester.java
+++ b/wicket-core/src/main/java/org/apache/wicket/util/tester/FormTester.java
@@ -754,7 +754,7 @@ public class FormTester
 		checkClosed();
 		try
 		{
-			tester.getLastRenderedPage().getSession().cleanupFeedbackMessages();
+			tester.clearFeedbackMessages();
 			tester.getRequest().setUseMultiPartContentType(workingForm.isMultiPart());
 			tester.submitForm(path);
 		}

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/FeedbackMessagesTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/FeedbackMessagesTest.java b/wicket-core/src/test/java/org/apache/wicket/FeedbackMessagesTest.java
index 90580a6..ef13cec 100644
--- a/wicket-core/src/test/java/org/apache/wicket/FeedbackMessagesTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/FeedbackMessagesTest.java
@@ -18,7 +18,6 @@ package org.apache.wicket;
 
 import junit.framework.Assert;
 
-import org.apache.wicket.feedback.FeedbackMessage;
 import org.junit.Test;
 
 /**
@@ -40,9 +39,6 @@ public class FeedbackMessagesTest extends WicketTestCase
 		page.debug("debug message");
 		page.info("info message");
 		page.error("error message");
-		Assert.assertTrue(tester.getLastRenderedPage()
-			.getSession()
-			.getFeedbackMessages()
-			.hasMessageFor(page, FeedbackMessage.ERROR));
+		Assert.assertTrue(tester.getLastRenderedPage().hasErrorMessage());
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/markup/html/form/LocalizedErrorMessageTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/LocalizedErrorMessageTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/LocalizedErrorMessageTest.java
index b7129b7..f410d3f 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/LocalizedErrorMessageTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/LocalizedErrorMessageTest.java
@@ -46,7 +46,7 @@ public class LocalizedErrorMessageTest extends WicketTestCase
 		tester.assertErrorMessages("'foo' in veld 'integer' moet een geheel getal zijn. ");
 		tester.getSession().setLocale(new Locale("us"));
 
-		tester.getSession().cleanupFeedbackMessages();
+		tester.clearFeedbackMessages();
 
 		page = new LocalizedMessagePage();
 		tester.startPage(page);
@@ -84,7 +84,7 @@ public class LocalizedErrorMessageTest extends WicketTestCase
 		tester.assertErrorMessages("'foo' ist kein g\u00FCltiger Wert f\u00FCr 'Integer'.");
 		tester.getSession().setLocale(new Locale("pl"));
 
-		tester.getSession().cleanupFeedbackMessages();
+		tester.clearFeedbackMessages();
 
 		page = new LocalizedMessagePage();
 		tester.startPage(page);

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ValidatorPropertiesTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ValidatorPropertiesTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ValidatorPropertiesTest.java
index 378e863..552893e 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ValidatorPropertiesTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/ValidatorPropertiesTest.java
@@ -86,65 +86,95 @@ public class ValidatorPropertiesTest extends WicketTestCase
 		page.getText14().validateRequired();
 
 		assertEquals("text1label is required", page.getText1()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("text2 is required", page.getText2()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("ok: text3333 is missing", page.getText3()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("ok: Text4Label is missing", page.getText4()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("ok: 555text555 is found in TestForm.properties", page.getText5()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text6 required", page.getText6()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text7-Label required", page.getText7()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text8-Label required", page.getText8()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("found it in panel", page.getText9()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("found it in form", page.getText10()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("found it in page", page.getText11()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("found it in page", page.getText12()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("found text-13 property", page.getText13()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text14 required", page.getText14()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 
 		// Test caching
 		assertEquals("Default message: text8-Label required", page.getText8()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 
@@ -181,57 +211,83 @@ public class ValidatorPropertiesTest extends WicketTestCase
 		page.getText12().validateRequired();
 
 		assertEquals("text1label is verplicht", page.getText1()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("text2 is verplicht", page.getText2()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("ok: text3333 mist", page.getText3()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("ok: Text4Label mist", page.getText4()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("gevonden in form", page.getText5()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text6 verplicht", page.getText6()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text7-Label verplicht", page.getText7()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("Default message: text8-Label verplicht", page.getText8()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("gevonden in panel", page.getText9()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("gevonden in form", page.getText10()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("gevonden in page", page.getText11()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 		assertEquals("gevonden in page", page.getText12()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 
 		// Test caching
 		assertEquals("Default message: text8-Label verplicht", page.getText8()
-			.getFeedbackMessage()
+			.getFeedbackMessages()
+			.iterator()
+			.next()
 			.getMessage()
 			.toString());
 	}

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/FormValidatorBehaviorTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/FormValidatorBehaviorTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/FormValidatorBehaviorTest.java
index 6f3eebe..7b0f3c4 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/FormValidatorBehaviorTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/FormValidatorBehaviorTest.java
@@ -20,6 +20,7 @@ import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.WicketTestCase;
 import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.feedback.FeedbackMessageCollector;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.IMarkupResourceStreamProvider;
 import org.apache.wicket.markup.html.WebPage;
@@ -72,7 +73,7 @@ public class FormValidatorBehaviorTest extends WicketTestCase
 		FormTester ft = tester.newFormTester("form");
 		ft.setValue("name", "999999999");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		MaxLenValidator max = new MaxLenValidator(page.name);
 		page.form.add(max);
@@ -80,18 +81,16 @@ public class FormValidatorBehaviorTest extends WicketTestCase
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "999999999");
 		ft.submit();
-		assertEquals(1, tester.getSession().getFeedbackMessages().size());
-		assertEquals("MAX", tester.getSession()
-			.getFeedbackMessages()
-			.iterator()
-			.next()
+		assertEquals(1, new FeedbackMessageCollector(page).collect().size());
+		assertEquals("MAX", new FeedbackMessageCollector(page).collect()
+			.get(0)
 			.getMessage()
 			.toString());
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "22");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		MinLenValidator min = new MinLenValidator(page.name);
 		page.form.add(min);
@@ -99,32 +98,30 @@ public class FormValidatorBehaviorTest extends WicketTestCase
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "22");
 		ft.submit();
-		assertEquals(1, tester.getSession().getFeedbackMessages().size());
-		assertEquals("MINIMUM", tester.getSession()
-			.getFeedbackMessages()
-			.iterator()
-			.next()
+		assertEquals(1, new FeedbackMessageCollector(page).collect().size());
+		assertEquals("MINIMUM", new FeedbackMessageCollector(page).collect()
+			.get(0)
 			.getMessage()
 			.toString());
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "7777777");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		page.form.remove(min);
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "22");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		page.form.remove(max);
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "999999999");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 	}
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/innerfeedback/LocalizedFeedbackBorder.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/innerfeedback/LocalizedFeedbackBorder.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/innerfeedback/LocalizedFeedbackBorder.java
index 1fb7b1a..e8952e7 100644
--- a/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/innerfeedback/LocalizedFeedbackBorder.java
+++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/form/validation/innerfeedback/LocalizedFeedbackBorder.java
@@ -17,8 +17,8 @@
 package org.apache.wicket.markup.html.form.validation.innerfeedback;
 
 import org.apache.wicket.AttributeModifier;
-import org.apache.wicket.Session;
 import org.apache.wicket.feedback.FeedbackMessage;
+import org.apache.wicket.feedback.FeedbackMessageCollector;
 import org.apache.wicket.feedback.IFeedbackMessageFilter;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.validation.FormComponentFeedbackBorder;
@@ -41,16 +41,17 @@ class LocalizedFeedbackBorder extends FormComponentFeedbackBorder
 			@Override
 			public String getObject()
 			{
-				boolean error = Session.get()
-					.getFeedbackMessages()
-					.hasMessage(new IFeedbackMessageFilter()
+				final IFeedbackMessageFilter filter = feedback.getFilter();
+
+				boolean error = new FeedbackMessageCollector(getPage()).collect(
+					new IFeedbackMessageFilter()
 					{
 						@Override
 						public boolean accept(FeedbackMessage message)
 						{
-							return feedback.getFilter().accept(message) && message.isError();
+							return filter.accept(message) && message.isError();
 						}
-					});
+					}).size() > 0;
 				return "border: 1px solid " + (error ? "red" : "green");
 			}
 		}));

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/util/tester/WicketTesterTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/tester/WicketTesterTest.java b/wicket-core/src/test/java/org/apache/wicket/util/tester/WicketTesterTest.java
index c539a52..c3e75e6 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/tester/WicketTesterTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/tester/WicketTesterTest.java
@@ -893,7 +893,7 @@ public class WicketTesterTest extends WicketTestCase
 
 		form.setValue("text", "XX");
 		setTextFieldAndAssertSubmit(false);
-		Session.get().cleanupFeedbackMessages();
+		tester.clearFeedbackMessages();
 
 		form.setValue("text", "XXXYYYXXX");
 		setTextFieldAndAssertSubmit(true);

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/util/tester/apps_4/FormTesterTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/tester/apps_4/FormTesterTest.java b/wicket-core/src/test/java/org/apache/wicket/util/tester/apps_4/FormTesterTest.java
index 169551e..d57aa0e 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/tester/apps_4/FormTesterTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/tester/apps_4/FormTesterTest.java
@@ -18,7 +18,6 @@ package org.apache.wicket.util.tester.apps_4;
 
 import java.util.List;
 
-import org.apache.wicket.Session;
 import org.apache.wicket.WicketTestCase;
 import org.apache.wicket.feedback.FeedbackMessage;
 import org.apache.wicket.util.tester.FormTester;
@@ -51,12 +50,15 @@ public class FormTesterTest extends WicketTestCase
 		page = (EmailPage)tester.getLastRenderedPage();
 
 		assertNull(page.getEmail());
-		assertTrue(Session.get().getFeedbackMessages().hasMessageFor(page.get("form:email")));
+		assertTrue(page.get("form:email").hasFeedbackMessage());
+
+		final List<FeedbackMessage> messages = page.get("form:email")
+			.getFeedbackMessages()
+			.toList();
 
-		final List<FeedbackMessage> messages =
-			Session.get().getFeedbackMessages().messagesForComponent(page.get("form:email"));
-		
 		assertEquals(1, messages.size());
-		assertEquals("wrong email address pattern for email", messages.get(0).getMessage().toString());
+		assertEquals("wrong email address pattern for email", messages.get(0)
+			.getMessage()
+			.toString());
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-core/src/test/java/org/apache/wicket/validation/ValidatorBehaviorTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/validation/ValidatorBehaviorTest.java b/wicket-core/src/test/java/org/apache/wicket/validation/ValidatorBehaviorTest.java
index 11c0b8a..56d0dfc 100644
--- a/wicket-core/src/test/java/org/apache/wicket/validation/ValidatorBehaviorTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/validation/ValidatorBehaviorTest.java
@@ -20,6 +20,7 @@ import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.WicketTestCase;
 import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.feedback.FeedbackMessageCollector;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.IMarkupResourceStreamProvider;
 import org.apache.wicket.markup.html.WebPage;
@@ -70,7 +71,7 @@ public class ValidatorBehaviorTest extends WicketTestCase
 		FormTester ft = tester.newFormTester("form");
 		ft.setValue("name", "999999999");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		MaxLenValidator max = new MaxLenValidator();
 		page.name.add(max);
@@ -78,18 +79,16 @@ public class ValidatorBehaviorTest extends WicketTestCase
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "999999999");
 		ft.submit();
-		assertEquals(1, tester.getSession().getFeedbackMessages().size());
-		assertEquals("MAX", tester.getSession()
-			.getFeedbackMessages()
-			.iterator()
-			.next()
+		assertEquals(1, new FeedbackMessageCollector(page).collect().size());
+		assertEquals("MAX", new FeedbackMessageCollector(page).collect()
+			.get(0)
 			.getMessage()
 			.toString());
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "22");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		MinLenValidator min = new MinLenValidator();
 		page.name.add(min);
@@ -97,32 +96,30 @@ public class ValidatorBehaviorTest extends WicketTestCase
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "22");
 		ft.submit();
-		assertEquals(1, tester.getSession().getFeedbackMessages().size());
-		assertEquals("MINIMUM", tester.getSession()
-			.getFeedbackMessages()
-			.iterator()
-			.next()
+		assertEquals(1, new FeedbackMessageCollector(page).collect().size());
+		assertEquals("MINIMUM", new FeedbackMessageCollector(page).collect()
+			.get(0)
 			.getMessage()
 			.toString());
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "7777777");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		page.name.remove(min);
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "22");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 
 		page.name.remove(max);
 
 		ft = tester.newFormTester("form");
 		ft.setValue("name", "999999999");
 		ft.submit();
-		assertEquals(0, tester.getSession().getFeedbackMessages().size());
+		assertEquals(0, new FeedbackMessageCollector(page).collect().size());
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/wicket/blob/27dcfc73/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
----------------------------------------------------------------------
diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
index 1ac5088..1486b1d 100644
--- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
+++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/ajax/markup/html/AjaxEditableLabel.java
@@ -25,6 +25,7 @@ import org.apache.wicket.ajax.AjaxEventBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
 import org.apache.wicket.ajax.attributes.JavaScriptPrecondition;
+import org.apache.wicket.feedback.FeedbackMessage;
 import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.head.IHeaderResponse;
@@ -44,14 +45,14 @@ import org.apache.wicket.validation.IValidator;
  * <p>
  * There are several methods that can be overridden for customization.
  * <ul>
- * <li>{@link #onEdit(org.apache.wicket.ajax.AjaxRequestTarget)} is called when the label is clicked and the editor is to
- * be displayed. The default implementation switches the label for the editor and places the caret
- * at the end of the text.</li>
- * <li>{@link #onSubmit(org.apache.wicket.ajax.AjaxRequestTarget)} is called when in edit mode, the user submitted new
- * content, that content validated well, and the model value successfully updated. This
- * implementation also clears any <code>window.status</code> set.</li>
- * <li>{@link #onError(org.apache.wicket.ajax.AjaxRequestTarget)} is called when in edit mode, the user submitted new
- * content, but that content did not validate. Get the current input by calling
+ * <li>{@link #onEdit(org.apache.wicket.ajax.AjaxRequestTarget)} is called when the label is clicked
+ * and the editor is to be displayed. The default implementation switches the label for the editor
+ * and places the caret at the end of the text.</li>
+ * <li>{@link #onSubmit(org.apache.wicket.ajax.AjaxRequestTarget)} is called when in edit mode, the
+ * user submitted new content, that content validated well, and the model value successfully
+ * updated. This implementation also clears any <code>window.status</code> set.</li>
+ * <li>{@link #onError(org.apache.wicket.ajax.AjaxRequestTarget)} is called when in edit mode, the
+ * user submitted new content, but that content did not validate. Get the current input by calling
  * {@link FormComponent#getInput()} on {@link #getEditor()}, and the error message by calling:
  * 
  * <pre>
@@ -61,9 +62,9 @@ import org.apache.wicket.validation.IValidator;
  * The default implementation of this method displays the error message in
  * <code>window.status</code>, redisplays the editor, selects the editor's content and sets the
  * focus on it.
- * <li>{@link #onCancel(org.apache.wicket.ajax.AjaxRequestTarget)} is called when in edit mode, the user choose not to
- * submit the contents (he/she pressed escape). The default implementation displays the label again
- * without any further action.</li>
+ * <li>{@link #onCancel(org.apache.wicket.ajax.AjaxRequestTarget)} is called when in edit mode, the
+ * user choose not to submit the contents (he/she pressed escape). The default implementation
+ * displays the label again without any further action.</li>
  * </ul>
  * </p>
  * 
@@ -305,35 +306,37 @@ public class AjaxEditableLabel<T> extends Panel
 		};
 		editor.setOutputMarkupId(true);
 		editor.setVisible(false);
-		editor.add(new EditorAjaxBehavior() {
+		editor.add(new EditorAjaxBehavior()
+		{
 			@Override
 			protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
 			{
 				super.updateAjaxAttributes(attributes);
 				attributes.setEventNames("blur", "keyup");
 
-				CharSequence dynamicExtraParameters =
-						"var result = {}, " +
-								"kc=Wicket.Event.keyCode(event)," +
-								"evtType=attrs.event.type;" +
-								"if (evtType === 'keyup') {" +
-								// ESCAPE key
-								"if (kc===27) { result.save = false }" +
-
-								// ENTER key
-								"else if (kc===13) { result = Wicket.Form.serializeElement(attrs.c); result.save = true; }" +
-								"}" +
-								"else if (evtType==='blur') { result = Wicket.Form.serializeElement(attrs.c); result.save = true; }" +
-								"return result;";
+				CharSequence dynamicExtraParameters = "var result = {}, "
+					+ "kc=Wicket.Event.keyCode(event),"
+					+ "evtType=attrs.event.type;"
+					+ "if (evtType === 'keyup') {"
+					+
+					// ESCAPE key
+					"if (kc===27) { result.save = false }"
+					+
+
+					// ENTER key
+					"else if (kc===13) { result = Wicket.Form.serializeElement(attrs.c); result.save = true; }"
+					+ "}"
+					+ "else if (evtType==='blur') { result = Wicket.Form.serializeElement(attrs.c); result.save = true; }"
+					+ "return result;";
 				attributes.getDynamicExtraParameters().add(dynamicExtraParameters);
 
-				CharSequence precondition =
-						"var kc=Wicket.Event.keyCode(event),"+
-								"evtType=attrs.event.type,"+
-								"ret=false;"+
-								"if(evtType==='blur' || (evtType==='keyup' && (kc===27 || kc===13))) ret = true;"+
-								"return ret;";
-				JavaScriptPrecondition javaScriptPrecondition = new JavaScriptPrecondition(precondition);
+				CharSequence precondition = "var kc=Wicket.Event.keyCode(event),"
+					+ "evtType=attrs.event.type,"
+					+ "ret=false;"
+					+ "if(evtType==='blur' || (evtType==='keyup' && (kc===27 || kc===13))) ret = true;"
+					+ "return ret;";
+				JavaScriptPrecondition javaScriptPrecondition = new JavaScriptPrecondition(
+					precondition);
 				attributes.getPreconditions().add(javaScriptPrecondition);
 
 			}
@@ -487,9 +490,9 @@ public class AjaxEditableLabel<T> extends Panel
 	 */
 	protected void onError(final AjaxRequestTarget target)
 	{
-		Serializable errorMessage = editor.getFeedbackMessage().getMessage();
-		if (errorMessage != null)
+		if (editor.hasErrorMessage())
 		{
+			Serializable errorMessage = editor.getFeedbackMessages().first(FeedbackMessage.ERROR);
 			target.appendJavaScript("window.status='" +
 				JavaScriptUtils.escapeQuotes(errorMessage.toString()) + "';");
 		}