You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by da...@apache.org on 2011/04/19 14:31:36 UTC

svn commit: r1095061 - in /wicket/trunk: wicket-core/src/main/java/org/apache/wicket/request/cycle/ wicket-core/src/test/java/org/apache/wicket/request/cycle/ wicket-util/src/main/java/org/apache/wicket/util/listener/

Author: dashorst
Date: Tue Apr 19 12:31:35 2011
New Revision: 1095061

URL: http://svn.apache.org/viewvc?rev=1095061&view=rev
Log:
Fixes WICKET-3625 Order of IRequestCycleListener invocations

Added:
    wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderApplication.java
    wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.html
    wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.java
    wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderTest.java
Modified:
    wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java
    wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java
    wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java
    wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java

Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java?rev=1095061&r1=1095060&r2=1095061&view=diff
==============================================================================
--- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java (original)
+++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java Tue Apr 19 12:31:35 2011
@@ -24,27 +24,23 @@ import org.apache.wicket.request.IReques
  */
 public abstract class AbstractRequestCycleListener implements IRequestCycleListener
 {
-	public void onRequestHandlerScheduled(IRequestHandler handler)
-	{
-	}
-
 	public void onBeginRequest(RequestCycle cycle)
 	{
 	}
 
-	public void onRequestHandlerResolved(IRequestHandler handler)
+	public void onEndRequest(RequestCycle cycle)
 	{
 	}
 
-	public void onEndRequest(RequestCycle cycle)
+	public void onDetach(RequestCycle cycle)
 	{
 	}
 
-	public void onDetach(RequestCycle cycle)
+	public void onRequestHandlerScheduled(IRequestHandler handler)
 	{
 	}
 
-	public void onExceptionRequestHandlerResolved(IRequestHandler handler, Exception exception)
+	public void onRequestHandlerResolved(IRequestHandler handler)
 	{
 	}
 
@@ -52,4 +48,8 @@ public abstract class AbstractRequestCyc
 	{
 		return null;
 	}
+
+	public void onExceptionRequestHandlerResolved(IRequestHandler handler, Exception exception)
+	{
+	}
 }

Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java?rev=1095061&r1=1095060&r2=1095061&view=diff
==============================================================================
--- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java (original)
+++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java Tue Apr 19 12:31:35 2011
@@ -32,34 +32,72 @@ import org.apache.wicket.request.IReques
  * of multi-threading issues.
  * <p>
  * <h3>Call order</h3>
+ * <p>
  * The interface methods are ordered in the execution order as Wicket goes through the request
  * cycle:
+ * </p>
  * <ol>
- * <li>{@link #onRequestHandlerScheduled(IRequestHandler)}</li>
  * <li>{@link #onBeginRequest(RequestCycle)}</li>
- * <li>{@link #onRequestHandlerResolved(IRequestHandler)}</li>
  * <li>{@link #onEndRequest(RequestCycle)}</li>
  * <li>{@link #onDetach(RequestCycle)}</li>
  * </ol>
- * <h3>Exception handling</h3>
- * When an exception occurs during request processing, the following call sequence is maintained:
- * <ol>
- * <li>{@link #onExceptionRequestHandlerResolved(IRequestHandler, Exception)}</li>
- * <li>{@link #onException(RequestCycle, Exception)}</li>
- * </ol>
+ * <p>
+ * The previous call sequence is valid for any Wicket request passing through the Wicket filter.
+ * Additionally when a request handler was resolved, a new handler scheduled, or an unhandled
+ * exception occurred during the request processing, any of the following can be called:
+ * </p>
+ * <ul>
+ * <li>{@link #onRequestHandlerResolved(IRequestHandler)}</li>
+ * <li>{@link #onRequestHandlerScheduled(IRequestHandler)}</li>
+ * <li>{@link #onException(RequestCycle, Exception)}, followed by
+ * {@link #onExceptionRequestHandlerResolved(IRequestHandler, Exception)}</li>
+ * </ul>
+ * 
+ * <h3>Implementing your own</h3>
+ * <p>
+ * Use {@link AbstractRequestCycleListener} for a default, empty implementation as a base class.
+ * </p>
+ * 
+ * <h3>Example</h3>
+ * <p>
+ * A short example of a request counter.
+ * </p>
+ * 
+ * <pre>
+ * public class RequestCounter extends AbstractRequestCycleListener
+ * {
+ * 	private AtomicLong counter = new AtomicLong(0);
+ * 
+ * 	public void onBeginRequest(RequestCycle cycle)
+ * 	{
+ * 		counter.incrementAndGet();
+ * 	}
+ * 
+ * 	public long getRequestCount()
+ * 	{
+ * 		return counter.longValue();
+ * 	}
+ * }
+ * 
+ * public class MyApplication extends WebApplication
+ * {
+ * 	public void init()
+ * 	{
+ * 		super.init();
+ * 		getRequestCycleListeners().add(new RequestCounter());
+ * 	}
+ * }
+ * </pre>
  * 
  * @author Jeremy Thomerson
+ * @author Martijn Dashorst
+ * 
+ * @see AbstractRequestCycleListener
  * @see Application#addRequestCycleListener(IRequestCycleListener)
- * @see RequestCycle#register(IRequestCycleListener)
  */
 public interface IRequestCycleListener
 {
 	/**
-	 * @param handler
-	 */
-	void onRequestHandlerScheduled(IRequestHandler handler);
-
-	/**
 	 * Called when the request cycle object is beginning its response
 	 * 
 	 * @param cycle
@@ -67,14 +105,6 @@ public interface IRequestCycleListener
 	void onBeginRequest(RequestCycle cycle);
 
 	/**
-	 * Called when an {@link IRequestHandler} is resolved and will be executed.
-	 * 
-	 * @param handler
-	 */
-	void onRequestHandlerResolved(IRequestHandler handler);
-
-
-	/**
 	 * Called when the request cycle object has finished its response
 	 * 
 	 * @param cycle
@@ -89,12 +119,20 @@ public interface IRequestCycleListener
 	void onDetach(RequestCycle cycle);
 
 	/**
-	 * Called when an {@link IRequestHandler} is resolved for an exception and will be executed.
+	 * Called when an {@link IRequestHandler} is resolved and will be executed.
 	 * 
 	 * @param handler
-	 * @param exception
 	 */
-	void onExceptionRequestHandlerResolved(IRequestHandler handler, Exception exception);
+	void onRequestHandlerResolved(IRequestHandler handler);
+
+	/**
+	 * Called when a {@link IRequestHandler} has been scheduled. Can be called multiple times during
+	 * a request when new handlers get scheduled for processing.
+	 * 
+	 * @param handler
+	 * @see RequestCycle#scheduleRequestHandlerAfterCurrent(IRequestHandler)
+	 */
+	void onRequestHandlerScheduled(IRequestHandler handler);
 
 	/**
 	 * Called when there is an exception in the request cycle that would normally be handled by
@@ -105,7 +143,7 @@ public interface IRequestCycleListener
 	 * 
 	 * @param cycle
 	 * 
-	 * @return request handler that will be exectued or {@code null} if none. If a request handler
+	 * @return request handler that will be executed or {@code null} if none. If a request handler
 	 *         is returned, it will override any configured exception mapper
 	 * 
 	 * @param ex
@@ -114,4 +152,11 @@ public interface IRequestCycleListener
 	 */
 	IRequestHandler onException(RequestCycle cycle, Exception ex);
 
-}
\ No newline at end of file
+	/**
+	 * Called when an {@link IRequestHandler} is resolved for an exception and will be executed.
+	 * 
+	 * @param handler
+	 * @param exception
+	 */
+	void onExceptionRequestHandlerResolved(IRequestHandler handler, Exception exception);
+}

Modified: wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java?rev=1095061&r1=1095060&r2=1095061&view=diff
==============================================================================
--- wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java (original)
+++ wicket/trunk/wicket-core/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java Tue Apr 19 12:31:35 2011
@@ -48,7 +48,7 @@ public class RequestCycleListenerCollect
 
 	public void onEndRequest(final RequestCycle cycle)
 	{
-		notify(new INotifier<IRequestCycleListener>()
+		reversedNotify(new INotifier<IRequestCycleListener>()
 		{
 			public void notify(IRequestCycleListener listener)
 			{
@@ -90,7 +90,7 @@ public class RequestCycleListenerCollect
 
 	public void onDetach(final RequestCycle cycle)
 	{
-		notify(new INotifier<IRequestCycleListener>()
+		reversedNotify(new INotifier<IRequestCycleListener>()
 		{
 			public void notify(IRequestCycleListener listener)
 			{

Added: wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderApplication.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderApplication.java?rev=1095061&view=auto
==============================================================================
--- wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderApplication.java (added)
+++ wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderApplication.java Tue Apr 19 12:31:35 2011
@@ -0,0 +1,92 @@
+/*
+ * 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.request.cycle;
+
+import java.util.ArrayList;
+
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.request.IRequestHandler;
+
+class MultiRequestCycleListenerCallOrderApplication extends WebApplication
+{
+	@Override
+	public Class<MultiRequestCycleListenerCallOrderPage> getHomePage()
+	{
+		return MultiRequestCycleListenerCallOrderPage.class;
+	}
+
+	@Override
+	public void init()
+	{
+		super.init();
+
+		getRequestCycleListeners().add(new CallRecordingListener("first"));
+		getRequestCycleListeners().add(new CallRecordingListener("second"));
+	}
+
+	public final ArrayList<String> callSequence = new ArrayList<String>();
+
+	/**
+	 * Records calls to each method in the {@code callSequence}.
+	 */
+	class CallRecordingListener implements IRequestCycleListener
+	{
+		private String name;
+
+		public CallRecordingListener(String name)
+		{
+			this.name = name;
+		}
+
+		public void onBeginRequest(RequestCycle cycle)
+		{
+			callSequence.add(name + ".onBeginRequest");
+		}
+
+		public void onRequestHandlerScheduled(IRequestHandler handler)
+		{
+			if (handler != null)
+				callSequence.add(name + ".onRequestHandlerScheduled");
+		}
+
+		public void onRequestHandlerResolved(IRequestHandler handler)
+		{
+			callSequence.add(name + ".onRequestHandlerResolved");
+		}
+
+		public void onEndRequest(RequestCycle cycle)
+		{
+			callSequence.add(name + ".onEndRequest");
+		}
+
+		public void onDetach(RequestCycle cycle)
+		{
+			callSequence.add(name + ".onDetach");
+		}
+
+		public void onExceptionRequestHandlerResolved(IRequestHandler handler, Exception exception)
+		{
+			callSequence.add(name + ".onExceptionRequestHandlerResolved");
+		}
+
+		public IRequestHandler onException(RequestCycle cycle, Exception ex)
+		{
+			callSequence.add(name + ".onException");
+			return null;
+		}
+	}
+}

Added: wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.html
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.html?rev=1095061&view=auto
==============================================================================
--- wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.html (added)
+++ wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.html Tue Apr 19 12:31:35 2011
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+	<head>
+	</head>
+	<body>
+	</body>
+</html>

Added: wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.java?rev=1095061&view=auto
==============================================================================
--- wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.java (added)
+++ wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderPage.java Tue Apr 19 12:31:35 2011
@@ -0,0 +1,28 @@
+/*
+ * 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.request.cycle;
+
+import org.apache.wicket.markup.html.WebPage;
+
+class MultiRequestCycleListenerCallOrderPage extends WebPage
+{
+	private static final long serialVersionUID = 1L;
+
+	public MultiRequestCycleListenerCallOrderPage()
+	{
+	}
+}

Added: wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderTest.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderTest.java?rev=1095061&view=auto
==============================================================================
--- wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderTest.java (added)
+++ wicket/trunk/wicket-core/src/test/java/org/apache/wicket/request/cycle/MultiRequestCycleListenerCallOrderTest.java Tue Apr 19 12:31:35 2011
@@ -0,0 +1,59 @@
+/*
+ * 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.request.cycle;
+
+import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Checks whether multiple registered requestcycle listeners are called in the right order:
+ * similarly to servlet filters.
+ */
+@SuppressWarnings("javadoc")
+public class MultiRequestCycleListenerCallOrderTest
+{
+	private WicketTester tester;
+	private MultiRequestCycleListenerCallOrderApplication application;
+
+	@Before
+	public void setUp()
+	{
+		application = new MultiRequestCycleListenerCallOrderApplication();
+		tester = new WicketTester(application);
+	}
+
+	@Test
+	public void callSequenceIsFirstInLastOut()
+	{
+		// start and render the test page
+		tester.startPage(new MultiRequestCycleListenerCallOrderPage());
+		// assert rendered page class
+		tester.assertRenderedPage(MultiRequestCycleListenerCallOrderPage.class);
+
+		assertThat(
+			application.callSequence,
+			is(equalTo(asList("first.onBeginRequest", "second.onBeginRequest",
+				"first.onRequestHandlerResolved", "second.onRequestHandlerResolved",
+				"second.onEndRequest", "first.onEndRequest", "second.onDetach", "first.onDetach"))));
+	}
+}

Modified: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java
URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java?rev=1095061&r1=1095060&r2=1095061&view=diff
==============================================================================
--- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java (original)
+++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java Tue Apr 19 12:31:35 2011
@@ -102,6 +102,27 @@ public abstract class ListenerCollection
 	}
 
 	/**
+	 * Notifies each listener in this in reversed order
+	 * 
+	 * @param notifier
+	 *            notifier used to notify each listener
+	 */
+	protected void reversedNotify(final INotifier<T> notifier)
+	{
+		reversedNotify(iterator(), notifier);
+	}
+
+	private void reversedNotify(Iterator<T> iterator, final INotifier<T> notifier)
+	{
+		if (iterator.hasNext())
+		{
+			T listener = iterator.next();
+			reversedNotify(iterator, notifier);
+			notifier.notify(listener);
+		}
+	}
+
+	/**
 	 * Removes a listener from this set.
 	 * 
 	 * @param listener