001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.request.cycle;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.apache.wicket.request.IRequestHandler;
023import org.apache.wicket.request.Url;
024import org.apache.wicket.util.listener.ListenerCollection;
025import org.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028/**
029 * Composite {@link IRequestCycleListener} that notifies all registered listeners with each
030 * IRequestCycleListener event.
031 * <p>
032 * Order of notification
033 *
034 * {@link #onBeginRequest(RequestCycle)}, {@link #onRequestHandlerScheduled(RequestCycle, IRequestHandler)} and
035 * {@link #onRequestHandlerResolved(RequestCycle, IRequestHandler)} are notified in first in, first out order.
036 * <p>
037 * {@link #onEndRequest(RequestCycle)} and {@link #onDetach(RequestCycle)} are notified in last in
038 * first out order (i.e. reversed order). So for these events the collection functions as a stack.
039 * <p>
040 * Exception handling
041 *
042 * The {@code RequestCycleListenerCollection} will use the first exception handler that is returned
043 * from all listeners in {@link #onException(RequestCycle, Exception)}
044 */
045public class RequestCycleListenerCollection extends ListenerCollection<IRequestCycleListener>
046        implements
047                IRequestCycleListener
048{
049        private static final Logger logger = LoggerFactory.getLogger(RequestCycleListenerCollection.class);
050        private static final long serialVersionUID = 1L;
051
052        /**
053         * Notifies all registered listeners of the onBeginRequest event in first in first out order,
054         * i.e. the listener that is the first element of this collection is the first listener to be
055         * notified of {@code onBeginRequest}.
056         */
057        @Override
058        public void onBeginRequest(final RequestCycle cycle)
059        {
060                notify(new INotifier<IRequestCycleListener>()
061                {
062                        @Override
063                        public void notify(IRequestCycleListener listener)
064                        {
065                                listener.onBeginRequest(cycle);
066                        }
067                });
068        }
069
070        /**
071         * Notifies all registered listeners of the {@code onEndRequest} event in first in last out
072         * order (i.e. the last listener that received an {@code #onBeginRequest} will be the first to
073         * get notified of an {@code onEndRequest}.
074         * 
075         * @see IRequestCycleListener#onEndRequest(RequestCycle)
076         */
077        @Override
078        public void onEndRequest(final RequestCycle cycle)
079        {
080                reversedNotify(new INotifier<IRequestCycleListener>()
081                {
082                        @Override
083                        public void notify(IRequestCycleListener listener)
084                        {
085                                listener.onEndRequest(cycle);
086                        }
087                });
088        }
089
090        /**
091         * Notifies all registered listeners of the {@code onDetach} event in first in last out order
092         * (i.e. the last listener that received an {@code #onBeginRequest} will be the first to get
093         * notified of an {@code onDetach}.
094         * 
095         * @see IRequestCycleListener#onDetach(RequestCycle)
096         */
097        @Override
098        public void onDetach(final RequestCycle cycle)
099        {
100                reversedNotifyIgnoringExceptions(new INotifier<IRequestCycleListener>()
101                {
102                        @Override
103                        public void notify(IRequestCycleListener listener)
104                        {
105                                listener.onDetach(cycle);
106                        }
107                });
108        }
109
110        /**
111         * Notifies all registered listeners of the exception and calls the first handler that was
112         * returned by the listeners.
113         * 
114         * @see IRequestCycleListener#onException(RequestCycle, Exception)
115         */
116        @Override
117        public IRequestHandler onException(final RequestCycle cycle, final Exception ex)
118        {
119                final List<IRequestHandler> handlers = new ArrayList<IRequestHandler>();
120
121                notify(new INotifier<IRequestCycleListener>()
122                {
123                        @Override
124                        public void notify(IRequestCycleListener listener)
125                        {
126                                IRequestHandler handler = listener.onException(cycle, ex);
127                                if (handler != null)
128                                {
129                                        handlers.add(handler);
130                                }
131                        }
132                });
133
134                if (handlers.isEmpty())
135                {
136                        return null;
137                }
138                if (handlers.size() > 1)
139                {
140                        logger.debug(
141                                "{} exception handlers available for exception {}, using the first handler",
142                                handlers.size(), ex);
143                }
144                return handlers.get(0);
145        }
146
147        @Override
148        public void onRequestHandlerResolved(final RequestCycle cycle, final IRequestHandler handler)
149        {
150                notify(new INotifier<IRequestCycleListener>()
151                {
152                        @Override
153                        public void notify(IRequestCycleListener listener)
154                        {
155                                listener.onRequestHandlerResolved(cycle, handler);
156                        }
157                });
158        }
159
160        @Override
161        public void onExceptionRequestHandlerResolved(final RequestCycle cycle,
162                final IRequestHandler handler, final Exception exception)
163        {
164                notify(new INotifier<IRequestCycleListener>()
165                {
166                        @Override
167                        public void notify(IRequestCycleListener listener)
168                        {
169                                listener.onExceptionRequestHandlerResolved(cycle, handler, exception);
170                        }
171                });
172        }
173
174        @Override
175        public void onRequestHandlerScheduled(final RequestCycle cycle, final IRequestHandler handler)
176        {
177                notify(new INotifier<IRequestCycleListener>()
178                {
179                        @Override
180                        public void notify(IRequestCycleListener listener)
181                        {
182                                listener.onRequestHandlerScheduled(cycle, handler);
183                        }
184                });
185        }
186
187        @Override
188        public void onRequestHandlerExecuted(final RequestCycle cycle, final IRequestHandler handler)
189        {
190                notify(new INotifier<IRequestCycleListener>()
191                {
192                        @Override
193                        public void notify(IRequestCycleListener listener)
194                        {
195                                listener.onRequestHandlerExecuted(cycle, handler);
196                        }
197                });
198        }
199
200        @Override
201        public void onUrlMapped(final RequestCycle cycle, final IRequestHandler handler, final Url url)
202        {
203                notify(new INotifier<IRequestCycleListener>()
204                {
205                        @Override
206                        public void notify(IRequestCycleListener listener)
207                        {
208                                listener.onUrlMapped(cycle, handler, url);
209                        }
210                });
211
212        }
213}