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.mock;
018
019import java.nio.charset.Charset;
020import java.nio.charset.StandardCharsets;
021import java.sql.Time;
022import java.time.Instant;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.List;
027import java.util.Locale;
028import java.util.Map;
029
030import javax.servlet.http.Cookie;
031
032import org.apache.wicket.WicketRuntimeException;
033import org.apache.wicket.request.Url;
034import org.apache.wicket.request.UrlUtils;
035import org.apache.wicket.request.http.WebRequest;
036
037/**
038 * Mutable mock {@link WebRequest}.
039 * 
040 * @author Matej Knopp
041 */
042public class MockWebRequest extends WebRequest
043{
044        private Url url;
045        private List<Cookie> cookies = new ArrayList<>();
046        private Map<String, List<Object>> headers = new HashMap<String, List<Object>>();
047        private MockRequestParameters postRequestParameters = new MockRequestParameters();
048        private Locale locale = Locale.getDefault();
049        private String contextPath;
050        private String filterPath;
051        private String prefixToContextPath = "";
052
053        /**
054         * Construct.
055         * 
056         * @param url
057         */
058        public MockWebRequest(Url url)
059        {
060                this.url = url;
061        }
062
063        /**
064         * Construct.
065         * 
066         * @param url
067         * @param contextPath
068         * @param filterPath
069         * @param prefixToContextPath
070         */
071        public MockWebRequest(Url url, String contextPath, String filterPath, String prefixToContextPath)
072        {
073                this.url = url;
074                this.contextPath = contextPath;
075                this.filterPath = filterPath;
076                this.prefixToContextPath = prefixToContextPath;
077        }
078
079        MockWebRequest(Url url, List<Cookie> cookies, Map<String, List<Object>> headers,
080                MockRequestParameters postRequestParameters, Locale locale)
081        {
082                this.url = url;
083                this.cookies.addAll(cookies);
084                this.headers = headers;
085                this.postRequestParameters = postRequestParameters;
086                this.locale = locale;
087        }
088
089        @Override
090        public MockWebRequest cloneWithUrl(Url url)
091        {
092                return new MockWebRequest(url, cookies, headers, postRequestParameters, locale);
093        }
094
095        /**
096         * @param url
097         */
098        public void setUrl(Url url)
099        {
100                this.url = url;
101        }
102
103        @Override
104        public Url getUrl()
105        {
106                return url;
107        }
108
109        @Override
110        public String toString()
111        {
112                return "MockWebRequest [url=" + url + "]";
113        }
114
115        /**
116         * Sets cookies for current request.
117         * 
118         * @param cookies
119         */
120        public void setCookies(List<Cookie> cookies)
121        {
122                this.cookies.clear();
123                this.cookies.addAll(cookies);
124        }
125
126        /**
127         * @param cookie
128         */
129        public void addCookie(Cookie cookie)
130        {
131                cookies.add(cookie);
132        }
133
134        @Override
135        public List<Cookie> getCookies()
136        {
137                return Collections.unmodifiableList(cookies);
138        }
139
140
141        @Override
142        public Instant getDateHeader(String name)
143        {
144                List<Object> dates = headers.get(name);
145                if (dates == null || dates.isEmpty())
146                {
147                        return null;
148                }
149
150                Object date = dates.get(0);
151
152                if (date instanceof Instant == false)
153                {
154                        throw new WicketRuntimeException("Date header with name '" + name +
155                                "' is not a valid Instant.");
156                }
157                return (Instant)date;
158        }
159
160        private void addHeaderObject(String name, Object value)
161        {
162                List<Object> values = headers.get(name);
163                if (values == null)
164                {
165                        values = new ArrayList<Object>();
166                        headers.put(name, values);
167                }
168                values.add(value);
169        }
170
171        /**
172         * Sets date header for given name.
173         * 
174         * @param name
175         * @param value
176         */
177        public void setDateHeader(String name, Time value)
178        {
179                removeHeader(name);
180                addHeaderObject(name, value);
181        }
182
183        /**
184         * Adds date header for given name.
185         * 
186         * @param name
187         * @param value
188         */
189        public void addDateHeader(String name, Time value)
190        {
191                addHeaderObject(name, value);
192        }
193
194        @Override
195        public String getHeader(String name)
196        {
197                List<Object> h = headers.get(name);
198                return (h == null || h.isEmpty()) ? null : h.get(0).toString();
199        }
200
201        /**
202         * Sets header for given name.
203         * 
204         * @param name
205         * @param value
206         */
207        public void setHeader(String name, String value)
208        {
209                removeHeader(name);
210                addHeader(name, value);
211        }
212
213        /**
214         * Adds header for given name.
215         * 
216         * @param name
217         * @param value
218         */
219        public void addHeader(String name, String value)
220        {
221                addHeaderObject(name, value);
222        }
223
224
225        /**
226         * Sets request locale.
227         * 
228         * @param locale
229         */
230        public void setLocale(Locale locale)
231        {
232                this.locale = locale;
233        }
234
235        @Override
236        public Locale getLocale()
237        {
238                return locale;
239        }
240
241        @Override
242        public List<String> getHeaders(String name)
243        {
244                List<String> res = new ArrayList<String>();
245                List<Object> values = headers.get(name);
246                if (values != null)
247                {
248                        for (Object value : values)
249                        {
250                                if (value != null)
251                                {
252                                        res.add(value.toString());
253                                }
254                        }
255                }
256                return res;
257        }
258
259        /**
260         * Removes header with specified name.
261         * 
262         * @param header
263         */
264        public void removeHeader(String header)
265        {
266                headers.remove(header);
267        }
268
269
270        @Override
271        public MockRequestParameters getPostParameters()
272        {
273                return postRequestParameters;
274        }
275
276        @Override
277        public Charset getCharset()
278        {
279                return StandardCharsets.UTF_8;
280        }
281
282        @Override
283        public Url getClientUrl()
284        {
285                Url baseUrl = new Url(url);
286                baseUrl.getQueryParameters().clear();
287                baseUrl.setContextRelative(url.isContextRelative());
288                return baseUrl;
289        }
290
291        @Override
292        public Object getContainerRequest()
293        {
294                return this;
295        }
296
297        @Override
298        public String getContextPath()
299        {
300                return UrlUtils.normalizePath(contextPath);
301        }
302
303        /**
304         * @param contextPath
305         * @return this
306         */
307        public MockWebRequest setContextPath(String contextPath)
308        {
309                this.contextPath = contextPath;
310                return this;
311        }
312
313        @Override
314        public String getFilterPath()
315        {
316                return UrlUtils.normalizePath(filterPath);
317        }
318
319        /**
320         * @param filterPath
321         * @return this
322         */
323        public MockWebRequest setFilterPath(String filterPath)
324        {
325                this.filterPath = filterPath;
326                return this;
327        }
328
329        @Override
330        public String getPrefixToContextPath()
331        {
332                return prefixToContextPath;
333        }
334
335        /**
336         * @param prefixToContextPath
337         * @return this
338         */
339        public MockWebRequest setPrefixToContextPath(String prefixToContextPath)
340        {
341                this.prefixToContextPath = prefixToContextPath;
342                return this;
343        }
344}