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;
018
019import java.io.Serializable;
020import java.util.ArrayList;
021import java.util.HashMap;
022import java.util.Iterator;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.wicket.request.IRequestHandler;
027import org.apache.wicket.request.IRequestMapper;
028import org.apache.wicket.request.IWritableRequestParameters;
029import org.apache.wicket.request.Request;
030import org.apache.wicket.request.Url;
031import org.apache.wicket.request.Url.QueryParameter;
032import org.apache.wicket.request.cycle.RequestCycle;
033import org.apache.wicket.request.flow.ResetResponseException;
034import org.apache.wicket.core.request.handler.PageProvider;
035import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
036import org.apache.wicket.core.request.handler.RenderPageRequestHandler.RedirectPolicy;
037import org.apache.wicket.request.http.WebRequest;
038import org.apache.wicket.request.mapper.parameter.PageParameters;
039import org.apache.wicket.util.string.StringValue;
040
041/**
042 * Causes Wicket to interrupt current request processing and immediately redirect to an intercept
043 * page.
044 */
045public class RestartResponseAtInterceptPageException extends ResetResponseException
046{
047        private static final long serialVersionUID = 1L;
048
049        /**
050         * Redirects to the specified {@code interceptPage}.
051         * 
052         * @param interceptPage
053         */
054        public RestartResponseAtInterceptPageException(Page interceptPage)
055        {
056                super(new RenderPageRequestHandler(new PageProvider(interceptPage),
057                        RedirectPolicy.AUTO_REDIRECT));
058                InterceptData.set();
059        }
060
061        /**
062         * Redirects to the specified intercept page, this will result in a bookmarkable redirect.
063         * 
064         * @param interceptPageClass
065         */
066        public RestartResponseAtInterceptPageException(Class<? extends Page> interceptPageClass)
067        {
068                this(interceptPageClass, null);
069        }
070
071        /**
072         * Redirects to the specified intercept page, this will result in a bookmarkable redirect.
073         * 
074         * @param interceptPageClass
075         * @param parameters
076         */
077        public RestartResponseAtInterceptPageException(Class<? extends Page> interceptPageClass,
078                PageParameters parameters)
079        {
080                super(new RenderPageRequestHandler(new PageProvider(interceptPageClass, parameters),
081                        RedirectPolicy.ALWAYS_REDIRECT));
082                InterceptData.set();
083        }
084
085        /**
086         * @return the url of the request when the interception happened or {@code null}
087         * or {@code null} if there was no interception yet
088         */
089        public static Url getOriginalUrl()
090        {
091                Url originalUrl = null;
092                InterceptData data = InterceptData.get();
093                if (data != null)
094                {
095                        originalUrl = data.getOriginalUrl();
096                }
097                return originalUrl;
098        }
099
100        /**
101         * @return the post parameters of thе request when the interception happened
102         * or {@code null} if there was no interception yet
103         */
104        public static Map<String, List<StringValue>> getOriginalPostParameters()
105        {
106                Map<String, List<StringValue>> postParameters = null;
107                InterceptData data = InterceptData.get();
108                if (data != null)
109                {
110                        postParameters = data.getPostParameters();
111                }
112                return postParameters;
113        }
114
115        /**
116         * INTERNAL CLASS, DO NOT USE
117         * 
118         * @author igor.vaynberg
119         */
120        static class InterceptData implements Serializable
121        {
122                private static final long serialVersionUID = 1L;
123
124                private Url originalUrl;
125                private Map<String, List<StringValue>> postParameters;
126
127                public Url getOriginalUrl()
128                {
129                        return originalUrl;
130                }
131
132                public Map<String, List<StringValue>> getPostParameters()
133                {
134                        return postParameters;
135                }
136
137                public static void set()
138                {
139                        Session session = Session.get();
140                        session.bind();
141                        InterceptData data = new InterceptData();
142                        Request request = RequestCycle.get().getRequest();
143                        data.originalUrl = request.getOriginalUrl();
144                        Iterator<QueryParameter> itor = data.originalUrl.getQueryParameters().iterator();
145                        while (itor.hasNext())
146                        {
147                                QueryParameter parameter = itor.next();
148                                String parameterName = parameter.getName();
149                                if (WebRequest.PARAM_AJAX.equals(parameterName) ||
150                                        WebRequest.PARAM_AJAX_BASE_URL.equals(parameterName) ||
151                                        WebRequest.PARAM_AJAX_REQUEST_ANTI_CACHE.equals(parameterName))
152                                {
153                                        itor.remove();
154                                }
155                        }
156
157                        data.postParameters = new HashMap<>();
158                        for (String s : request.getPostParameters().getParameterNames())
159                        {
160                                if (WebRequest.PARAM_AJAX.equals(s) || WebRequest.PARAM_AJAX_BASE_URL.equals(s) ||
161                                        WebRequest.PARAM_AJAX_REQUEST_ANTI_CACHE.equals(s))
162                                {
163                                        continue;
164                                }
165                                data.postParameters.put(s, new ArrayList<>(request.getPostParameters()
166                                        .getParameterValues(s)));
167                        }
168                        session.setMetaData(key, data);
169                }
170
171                public static InterceptData get()
172                {
173                        if (Session.exists())
174                        {
175                                return Session.get().getMetaData(key);
176                        }
177                        return null;
178                }
179
180                public static void clear()
181                {
182                        if (Session.exists())
183                        {
184                                Session.get().setMetaData(key, null);
185                        }
186                }
187
188                private static final MetaDataKey<InterceptData> key = new MetaDataKey<>()
189                {
190                        private static final long serialVersionUID = 1L;
191                };
192        }
193
194        static void continueToOriginalDestination()
195        {
196                InterceptData data = InterceptData.get();
197                if (data != null)
198                {
199                        String url = RequestCycle.get().getUrlRenderer().renderUrl(data.originalUrl);
200                        throw new NonResettingRestartException(url);
201                }
202        }
203
204        static void clearOriginalDestination()
205        {
206                InterceptData.clear();
207        }
208
209        static IRequestMapper MAPPER = new IRequestMapper()
210        {
211                @Override
212                public int getCompatibilityScore(Request request)
213                {
214                        return matchedData(request) != null ? Integer.MAX_VALUE : 0;
215                }
216
217                @Override
218                public Url mapHandler(IRequestHandler requestHandler)
219                {
220                        return null;
221                }
222
223                @Override
224                public IRequestHandler mapRequest(Request request)
225                {
226                        InterceptData data = matchedData(request);
227                        if (data != null)
228                        {
229                                if (data.postParameters.isEmpty() == false &&
230                                        request.getPostParameters() instanceof IWritableRequestParameters)
231                                {
232                                        IWritableRequestParameters parameters = (IWritableRequestParameters)request.getPostParameters();
233                                        parameters.reset();
234                                        for (String s : data.postParameters.keySet())
235                                        {
236                                                parameters.setParameterValues(s, data.postParameters.get(s));
237                                        }
238                                }
239                                InterceptData.clear();
240                        }
241                        return null;
242                }
243
244                private InterceptData matchedData(Request request)
245                {
246                        InterceptData data = InterceptData.get();
247                        if (data != null && data.originalUrl.equals(request.getOriginalUrl()))
248                        {
249                                return data;
250                        }
251                        return null;
252                }
253        };
254}