Author: ivaynberg Date: Thu Oct 21 05:51:50 2010 New Revision: 1025834 URL: http://svn.apache.org/viewvc?rev=1025834&view=rev Log: abstracted the idea of a listener collection refactored listener lists to use the collection instead removed detachlistener in favor of ondetach in request cycle listener request cycle listener now gets the request cycle for context Issue: WICKET-3125
Added: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java (contents, props changed) - copied, changed from r1025821, wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerSet.java wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java (with props) wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java (with props) wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java (with props) Removed: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/IListener.java wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerSet.java Modified: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ChangeListenerSet.java wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/IChangeListener.java wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java wicket/trunk/wicket/src/test/java/org/apache/wicket/request/cycle/RequestCycleListenerTest.java Modified: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ChangeListenerSet.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ChangeListenerSet.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ChangeListenerSet.java (original) +++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ChangeListenerSet.java Thu Oct 21 05:51:50 2010 @@ -24,14 +24,26 @@ package org.apache.wicket.util.listener; * * @author Jonathan Locke */ -public final class ChangeListenerSet extends ListenerSet<IChangeListener> +public final class ChangeListenerSet extends ListenerCollection<IChangeListener> { /** - * @see org.apache.wicket.util.listener.ListenerSet#notifyListener(org.apache.wicket.util.listener.IListener) + * @see org.apache.wicket.util.listener.ListenerCollection#notifyListener(org.apache.wicket.util.listener.IListener) */ - @Override protected void notifyListener(IChangeListener listener) { - listener.onChange(); + + } + + public void notifyListeners() + { + notify(new INotifier<IChangeListener>() + { + + public void notify(IChangeListener object) + { + object.onChange(); + } + + }); } } Modified: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/IChangeListener.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/IChangeListener.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/IChangeListener.java (original) +++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/IChangeListener.java Thu Oct 21 05:51:50 2010 @@ -21,7 +21,7 @@ package org.apache.wicket.util.listener; * * @author Jonathan Locke */ -public interface IChangeListener extends IListener +public interface IChangeListener { /** * Client method that is called to indicate that something changed. Copied: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java (from r1025821, wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerSet.java) URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java?p2=wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java&p1=wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerSet.java&r1=1025821&r2=1025834&rev=1025834&view=diff ============================================================================== --- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerSet.java (original) +++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java Thu Oct 21 05:51:50 2010 @@ -16,50 +16,85 @@ */ package org.apache.wicket.util.listener; -import java.util.HashSet; -import java.util.Set; +import java.io.Serializable; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * Holds a set of listeners implementing the IListener tag interface. Subclasses can implement - * notification methods that cast the listener to the correct subinterface and invoke the - * appropriate listener method. - * - * Note that these classes are not meant to be serializable or for you to hold them in session (see - * WICKET-2697) + * Represents a collection of listeners. Facilitates invocation of events on each listener. + * <p> + * NOTE: Ordering of listeners is not guaranteed and should not be relied upon + * </p> * + * @autor ivaynberg (Igor Vaynberg) * @author Jonathan Locke * * @param <T> + * type of listeners */ -public abstract class ListenerSet<T extends IListener> +public abstract class ListenerCollection<T> implements Serializable { - /** Set of change listeners */ - private final Set<T> listeners = new HashSet<T>(); + private static final Logger logger = LoggerFactory.getLogger(ListenerCollection.class); + + /** list of listeners */ + private final List<T> listeners = new CopyOnWriteArrayList<T>(); /** * Adds a listener to this set of listeners. * * @param listener * The listener to add - * @return <tt>true</tt> if the set did not already contain the specified listener. + * @return {...@code true} if the listener was added */ public boolean add(final T listener) { - return listeners.add(listener); + if (listener == null && !isAllowingNulls()) + { + return false; + } + if (!isAllowingDuplicates() && listeners.contains(listener)) + { + return false; + } + listeners.add(listener); + return true; } /** - * Notifies each listener in this set by calling notifyListener. + * Notifies each listener in this + * + * @param notifier + * notifier used to notify each listener */ - public void notifyListeners() + protected void notify(INotifier<T> notifier) { - // Create a stable copy for iterating over - final Set<T> copy = new HashSet<T>(listeners); + for (T listener : listeners) + { + notifier.notify(listener); + } + } - // Notify all listeners that the file changed - for (T listener : copy) + /** + * Notifies each listener in this set ignoring exceptions. Exceptions will be logged. + * + * @param notifier + * notifier used to notify each listener + */ + protected void notifyIgnoringExceptions(INotifier<T> notifier) + { + for (T listener : listeners) { - notifyListener(listener); + try + { + notifier.notify(listener); + } + catch (Exception e) + { + logger.error("Error invoking listener: " + listener, e); + } } } @@ -75,10 +110,35 @@ public abstract class ListenerSet<T exte } /** - * Notifies a listener. + * Whether or not added listeners should be checked for duplicates. * - * @param listener - * The listener to notify + * @return {...@code true} to ignore duplicates */ - protected abstract void notifyListener(T listener); + protected boolean isAllowingDuplicates() + { + return true; + } + + /** + * Whether or not to allow {...@code null}s in listener collection. + * + * @return {...@code} true to allow nulls to be added to the collection + */ + protected boolean isAllowingNulls() + { + return false; + } + + /** + * Used to notify a listener. Usually this method simply forwards the {...@link #notify(Object)} to + * the proper method on the listener. + * + * @author ivaynberg (Igor Vaynberg) + * @param <T> + */ + protected static interface INotifier<T> + { + void notify(T listener); + } + } Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/listener/ListenerCollection.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java (original) +++ wicket/trunk/wicket-util/src/main/java/org/apache/wicket/util/watch/ModificationWatcher.java Thu Oct 21 05:51:50 2010 @@ -118,7 +118,7 @@ public class ModificationWatcher impleme else { // Add listener to existing entry - return entry.listeners.add(listener); + return !entry.listeners.add(listener); } } Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java (original) +++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Application.java Thu Oct 21 05:51:50 2010 @@ -65,9 +65,11 @@ import org.apache.wicket.request.IReques import org.apache.wicket.request.Request; import org.apache.wicket.request.Response; import org.apache.wicket.request.component.IRequestablePage; +import org.apache.wicket.request.cycle.AbstractRequestCycleListener; +import org.apache.wicket.request.cycle.IRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycle; -import org.apache.wicket.request.cycle.RequestCycle.IRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycleContext; +import org.apache.wicket.request.cycle.RequestCycleListenerCollection; import org.apache.wicket.request.mapper.CompoundRequestMapper; import org.apache.wicket.request.mapper.ICompoundRequestMapper; import org.apache.wicket.request.mapper.IMapperContext; @@ -170,7 +172,7 @@ public abstract class Application implem /** */ private List<IComponentOnAfterRenderListener> componentOnAfterRenderListeners; - private final List<IRequestCycleListener> requestCycleListeners = new ArrayList<IRequestCycleListener>(); + private final RequestCycleListenerCollection requestCycleListeners = new RequestCycleListenerCollection(); /** root mapper */ private IRequestMapper rootRequestMapper; @@ -1165,9 +1167,9 @@ public abstract class Application implem /** * @return the unmodifiable request list of {...@link IRequestCycleListener}s in this application */ - public List<IRequestCycleListener> getRequestCycleListeners() + public RequestCycleListenerCollection getRequestCycleListeners() { - return Collections.unmodifiableList(requestCycleListeners); + return requestCycleListeners; } @@ -1493,7 +1495,8 @@ public abstract class Application implem getRootRequestMapper(), newExceptionMapper()); RequestCycle requestCycle = getRequestCycleProvider().get(context); - requestCycle.register(new RequestCycle.DetachCallback() + requestCycle.getListeners().add(requestCycleListeners); + requestCycle.getListeners().add(new AbstractRequestCycleListener() { public void onDetach(RequestCycle requestCycle) { Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java (original) +++ wicket/trunk/wicket/src/main/java/org/apache/wicket/Session.java Thu Oct 21 05:51:50 2010 @@ -33,6 +33,7 @@ import org.apache.wicket.feedback.Feedba import org.apache.wicket.page.IPageManager; import org.apache.wicket.request.ClientInfo; import org.apache.wicket.request.Request; +import org.apache.wicket.request.cycle.AbstractRequestCycleListener; import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.session.ISessionStore; import org.apache.wicket.util.lang.Objects; @@ -440,9 +441,10 @@ public abstract class Session implements { if (sessionInvalidated == false) { - RequestCycle.get().register(new RequestCycle.DetachCallback() + RequestCycle.get().getListeners().add(new AbstractRequestCycleListener() { - public void onDetach(final RequestCycle requestCycle) + @Override + public void onDetach(final RequestCycle cycle) { destroy(); } Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java?rev=1025834&view=auto ============================================================================== --- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java (added) +++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java Thu Oct 21 05:51:50 2010 @@ -0,0 +1,36 @@ +/* + * 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; + +public abstract class AbstractRequestCycleListener implements IRequestCycleListener +{ + public void onBeginRequest(final RequestCycle cycle) + { + } + + public void onDetach(final RequestCycle cycle) + { + } + + public void onEndRequest(final RequestCycle cycle) + { + } + + public void onException(final RequestCycle cycle, Exception ex) + { + } +} Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/AbstractRequestCycleListener.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java?rev=1025834&view=auto ============================================================================== --- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java (added) +++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java Thu Oct 21 05:51:50 2010 @@ -0,0 +1,55 @@ +package org.apache.wicket.request.cycle; + +import org.apache.wicket.Application; + +/** + * A callback interface for various methods in the request cycle. If you are creating a framework + * that needs to do something in this methods, rather than extending RequestCycle or one of its + * subclasses, you should implement this callback and allow users to add your listener to their + * custom request cycle. + * + * These listeners can be added directly to the request cycle when it is created or to the + * {...@link Application} + * + * @author Jeremy Thomerson + * @see Application#addRequestCycleListener(IRequestCycleListener) + * @see RequestCycle#register(IRequestCycleListener) + */ +public interface IRequestCycleListener +{ + /** + * Called when the request cycle object is beginning its response + * + * @param cycle + */ + void onBeginRequest(RequestCycle cycle); + + /** + * Called when the request cycle object has finished its response + * + * @param cycle + */ + void onEndRequest(RequestCycle cycle); + + /** + * Called after the request cycle has been detached + * + * @param cycle + */ + void onDetach(RequestCycle cycle); + + /** + * Called when there is an exception in the request cycle that would normally be handled by + * {...@link RequestCycle#handleException(Exception)} + * + * Note that in the event of an exception, {...@link #onEndRequest()} will still be called after + * these listeners have {...@link #onException(Exception)} called + * + * @param cycle + * + * @param ex + * the exception that was passed in to + * {...@link RequestCycle#handleException(Exception)} + */ + void onException(RequestCycle cycle, Exception ex); +} \ No newline at end of file Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/IRequestCycleListener.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java (original) +++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycle.java Thu Oct 21 05:51:50 2010 @@ -16,10 +16,6 @@ */ package org.apache.wicket.request.cycle; -import java.util.ArrayList; -import java.util.List; - -import org.apache.wicket.Application; import org.apache.wicket.MetaDataEntry; import org.apache.wicket.MetaDataKey; import org.apache.wicket.Page; @@ -71,61 +67,6 @@ public class RequestCycle extends Reques private boolean cleanupFeedbackMessagesOnDetach = true; - /** - * Custom callback invoked on request cycle detach. Detach callbacks are invoked after all - * {...@link IRequestHandler}s are detached. - * - * @author Matej Knopp - */ - public interface DetachCallback - { - /** - * Invoked on request cycle detach. - * - * @param requestCycle - */ - public void onDetach(RequestCycle requestCycle); - } - - /** - * A callback interface for various methods in the request cycle. If you are creating a - * framework that needs to do something in this methods, rather than extending RequestCycle or - * one of its subclasses, you should implement this callback and allow users to add your - * listener to their custom request cycle. - * - * These listeners can be added directly to the request cycle when it is created or to the - * {...@link Application} - * - * @author Jeremy Thomerson - * @see Application#addRequestCycleListener(IRequestCycleListener) - * @see RequestCycle#register(IRequestCycleListener) - */ - public interface IRequestCycleListener - { - /** - * Called when the request cycle object is beginning its response - */ - void onBeginRequest(); - - /** - * Called when the request cycle object has finished its response - */ - void onEndRequest(); - - /** - * Called when there is an exception in the request cycle that would normally be handled by - * {...@link RequestCycle#handleException(Exception)} - * - * Note that in the event of an exception, {...@link #onEndRequest()} will still be called - * after these listeners have {...@link #onException(Exception)} called - * - * @param ex - * the exception that was passed in to - * {...@link RequestCycle#handleException(Exception)} - */ - void onException(Exception ex); - } - private interface IExecutor<T> { @@ -160,9 +101,7 @@ public class RequestCycle extends Reques private final IExceptionMapper exceptionMapper; - private final List<DetachCallback> detachCallbacks = new ArrayList<DetachCallback>(); - - private final List<IRequestCycleListener> requestCycleListeners = new ArrayList<IRequestCycleListener>(); + private final RequestCycleListenerCollection listeners = new RequestCycleListenerCollection(); private UrlRenderer urlRenderer; @@ -304,13 +243,7 @@ public class RequestCycle extends Reques boolean result; try { - callRequestCycleListeners(new IExecutor<IRequestCycleListener>() - { - public void execute(IRequestCycleListener rcl) - { - rcl.onBeginRequest(); - } - }, "onBeginRequest"); + listeners.onBeginRequest(this); onBeginRequest(); result = processRequest(); } @@ -321,26 +254,6 @@ public class RequestCycle extends Reques return result; } - private void callRequestCycleListeners(IExecutor<IRequestCycleListener> executor, String method) - { - List<IRequestCycleListener> app = Application.get().getRequestCycleListeners(); - int size = requestCycleListeners.size() + app.size(); - List<IRequestCycleListener> listeners = new ArrayList<IRequestCycleListener>(size); - listeners.addAll(app); - listeners.addAll(requestCycleListeners); - for (IRequestCycleListener rcl : listeners) - { - try - { - executor.execute(rcl); - } - catch (Exception ex) - { - log.error("Error executing " + method + " on IRequestCycleListener", ex); - } - } - } - /** * * @param handler @@ -377,13 +290,7 @@ public class RequestCycle extends Reques */ protected IRequestHandler handleException(final Exception e) { - callRequestCycleListeners(new IExecutor<RequestCycle.IRequestCycleListener>() - { - public void execute(IRequestCycleListener object) - { - object.onException(e); - } - }, "onException"); + listeners.onException(this, e); return exceptionMapper.map(e); } @@ -578,14 +485,8 @@ public class RequestCycle extends Reques try { - callRequestCycleListeners(new IExecutor<IRequestCycleListener>() - { - public void execute(IRequestCycleListener rcl) - { - rcl.onEndRequest(); - } - }, "onEndRequest"); onEndRequest(); + listeners.onEndRequest(this); } catch (RuntimeException e) { @@ -598,43 +499,12 @@ public class RequestCycle extends Reques } finally { - for (DetachCallback c : detachCallbacks) - { - try - { - c.onDetach(this); - } - catch (Exception e) - { - log.error("Error detaching DetachCallback", e); - } - } + listeners.onDetach(this); set(null); } } /** - * Registers a callback to be invoked on {...@link RequestCycle} detach. The callback will be - * invoked after all {...@link IRequestHandler}s are detached. - * - * @param detachCallback - */ - public void register(DetachCallback detachCallback) - { - detachCallbacks.add(detachCallback); - } - - /** - * Registers a listener to extend functionality in the {...@link RequestCycle}. - * - * @param listener - */ - public void register(IRequestCycleListener listener) - { - requestCycleListeners.add(listener); - } - - /** * Convenience method for setting next page to be rendered. * * @param page @@ -721,5 +591,9 @@ public class RequestCycle extends Reques { } + public RequestCycleListenerCollection getListeners() + { + return listeners; + } } Added: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java?rev=1025834&view=auto ============================================================================== --- wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java (added) +++ wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java Thu Oct 21 05:51:50 2010 @@ -0,0 +1,81 @@ +/* + * 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.util.listener.ListenerCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RequestCycleListenerCollection extends ListenerCollection<IRequestCycleListener> + implements + IRequestCycleListener +{ + private static final Logger logger = LoggerFactory.getLogger(RequestCycleListenerCollection.class); + + public void onBeginRequest(final RequestCycle cycle) + { + notify(new INotifier<IRequestCycleListener>() + { + public void notify(IRequestCycleListener listener) + { + listener.onBeginRequest(cycle); + } + }); + } + + public void onEndRequest(final RequestCycle cycle) + { + notify(new INotifier<IRequestCycleListener>() + { + public void notify(IRequestCycleListener listener) + { + listener.onEndRequest(cycle); + } + }); + } + + public void onException(final RequestCycle cycle, final Exception ex) + { + notify(new INotifier<IRequestCycleListener>() + { + public void notify(IRequestCycleListener listener) + { + listener.onException(cycle, ex); + } + }); + + } + + public void onDetach(final RequestCycle cycle) + { + notify(new INotifier<IRequestCycleListener>() + { + public void notify(IRequestCycleListener listener) + { + try + { + listener.onDetach(cycle); + } + catch (Exception e) + { + logger.error("Error detaching request cycle listener: " + listener, e); + } + } + }); + } + +} Propchange: wicket/trunk/wicket/src/main/java/org/apache/wicket/request/cycle/RequestCycleListenerCollection.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: wicket/trunk/wicket/src/test/java/org/apache/wicket/request/cycle/RequestCycleListenerTest.java URL: http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/request/cycle/RequestCycleListenerTest.java?rev=1025834&r1=1025833&r2=1025834&view=diff ============================================================================== --- wicket/trunk/wicket/src/test/java/org/apache/wicket/request/cycle/RequestCycleListenerTest.java (original) +++ wicket/trunk/wicket/src/test/java/org/apache/wicket/request/cycle/RequestCycleListenerTest.java Thu Oct 21 05:51:50 2010 @@ -26,7 +26,6 @@ import org.apache.wicket.request.IReques import org.apache.wicket.request.Request; import org.apache.wicket.request.Response; import org.apache.wicket.request.Url; -import org.apache.wicket.request.cycle.RequestCycle.IRequestCycleListener; import org.apache.wicket.resource.DummyApplication; /** @@ -34,20 +33,21 @@ import org.apache.wicket.resource.DummyA */ public class RequestCycleListenerTest extends BaseRequestHandlerStackTest { - private int begins, ends, exceptions, exceptionsMapped, responses, detaches = 0; - private RequestCycle cycle; + + private int begins, ends, exceptions, exceptionsMapped, responses, detaches, + detachesnotified = 0; + private IRequestHandler handler; @Override protected void setUp() throws Exception { super.setUp(); - setupNewRequestCycle(false); ThreadContext.setApplication(new DummyApplication()); } - private void setupNewRequestCycle(final boolean throwExceptionInRespond) + private RequestCycle newRequestCycle(final boolean throwExceptionInRespond) { final Response originalResponse = newResponse(); Request request = new MockWebRequest(Url.parse("http://wicket.apache.org")); @@ -94,7 +94,15 @@ public class RequestCycleListenerTest ex }; RequestCycleContext context = new RequestCycleContext(request, originalResponse, requestMapper, exceptionMapper); - cycle = new RequestCycle(context); + + RequestCycle cycle = new RequestCycle(context); + + if (Application.exists()) + { + cycle.getListeners().add(Application.get().getRequestCycleListeners()); + } + + return cycle; } /** @@ -102,19 +110,22 @@ public class RequestCycleListenerTest ex */ public void testBasicOperations() throws Exception { - Application.get().addRequestCycleListener(newIncrementingListener()); - assertValues(0, 0, 0, 0, 0, 0); + Application.get().addRequestCycleListener(new IncrementingListener()); + + RequestCycle cycle = newRequestCycle(false); + + assertValues(0, 0, 0, 0, 0, 0, 0); /* * begins, ends, responses and detaches should increment by one because we have one listener * * exceptions should not increment because none are thrown */ cycle.processRequestAndDetach(); - assertValues(1, 1, 0, 0, 1, 1); + assertValues(1, 1, 0, 0, 1, 1, 1); // TEST WITH TWO LISTENERS - setupNewRequestCycle(false); - cycle.register(newIncrementingListener()); + cycle = newRequestCycle(false); + cycle.getListeners().add(new IncrementingListener()); /* * we now have two listeners (app and cycle) * @@ -125,11 +136,11 @@ public class RequestCycleListenerTest ex * responses and detaches should increment by one */ cycle.processRequestAndDetach(); - assertValues(3, 3, 0, 0, 2, 2); + assertValues(3, 3, 0, 0, 2, 2, 3); // TEST WITH TWO LISTENERS AND AN EXCEPTION DURING RESPONSE - setupNewRequestCycle(true); - cycle.register(newIncrementingListener()); + cycle = newRequestCycle(true); + cycle.getListeners().add(new IncrementingListener()); /* * begins and ends should increment by two (once for each listener) * @@ -142,11 +153,35 @@ public class RequestCycleListenerTest ex * detaches should increment by one */ cycle.processRequestAndDetach(); - assertValues(5, 5, 2, 1, 2, 3); + assertValues(5, 5, 2, 1, 2, 3, 5); + } + + /** + * @throws Exception + */ + public void testExceptionHandingInOnDetach() throws Exception + { + // this test is a little flaky because it depends on the ordering of listeners which is not + // guaranteed + RequestCycle cycle = newRequestCycle(false); + cycle.getListeners().add(new IncrementingListener()); + cycle.getListeners().add(new IncrementingListener() + { + @Override + public void onDetach(final RequestCycle cycle) + { + super.onDetach(cycle); + throw new RuntimeException(); + } + }); + cycle.getListeners().add(new IncrementingListener()); + cycle.processRequestAndDetach(); + assertValues(3, 3, 0, 0, 1, 1, 3); } + private void assertValues(int begins, int ends, int exceptions, int exceptionsMapped, - int responses, int detaches) + int responses, int detaches, int detachesnotified) { assertEquals(begins, this.begins); assertEquals(ends, this.ends); @@ -154,26 +189,31 @@ public class RequestCycleListenerTest ex assertEquals(exceptionsMapped, this.exceptionsMapped); assertEquals(responses, this.responses); assertEquals(detaches, this.detaches); + assertEquals(detachesnotified, this.detachesnotified); } - private IRequestCycleListener newIncrementingListener() + private class IncrementingListener implements IRequestCycleListener { - return new IRequestCycleListener() + public void onException(final RequestCycle cycle, Exception ex) { - public void onException(Exception ex) - { - exceptions++; - } + exceptions++; + } - public void onEndRequest() - { - ends++; - } + public void onEndRequest(final RequestCycle cycle) + { + ends++; + } - public void onBeginRequest() - { - begins++; - } - }; + public void onBeginRequest(final RequestCycle cycle) + { + begins++; + } + + public void onDetach(final RequestCycle cycle) + { + detachesnotified++; + } } + + }