001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.mock;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.io.*;
018import java.security.*;
019import java.util.*;
020
021import javax.servlet.*;
022import javax.servlet.http.*;
023
024import org.apache.juneau.internal.*;
025import org.apache.juneau.rest.*;
026import org.apache.juneau.rest.util.*;
027import org.apache.juneau.urlencoding.*;
028import org.apache.juneau.utils.*;
029
030/**
031 * An implementation of {@link HttpServletRequest} for mocking purposes.
032 *
033 * <h5 class='section'>See Also:</h5>
034 * <ul>
035 *    <li class='link'>{@doc juneau-rest-server.UnitTesting}
036 * </ul>
037 */
038public class MockServletRequest implements HttpServletRequest, MockHttpRequest {
039
040   private String method = "GET";
041   private Map<String,String[]> queryData;
042   private Map<String,String[]> formDataMap;
043   private Map<String,String[]> headerMap = new LinkedHashMap<>();
044   private Map<String,Object> attributeMap = new LinkedHashMap<>();
045   private String characterEncoding = "UTF-8";
046   private byte[] body = new byte[0];
047   private String protocol = "HTTP/1.1";
048   private String scheme = "http";
049   private String serverName = "localhost";
050   private int serverPort = 8080;
051   private String remoteAddr = "";
052   private String remoteHost = "";
053   private Locale locale = Locale.ENGLISH;
054   private String realPath;
055   private int remotePort;
056   private String localName;
057   private String localAddr;
058   private int localPort;
059   private RequestDispatcher requestDispatcher;
060   private ServletContext servletContext;
061   private DispatcherType dispatcherType;
062   private String authType;
063   private Cookie[] cookies;
064   private String pathInfo;
065   private String pathTranslated;
066   private String contextPath = "";
067   private String queryString;
068   private String remoteUser;
069   private Principal userPrincipal;
070   private String requestedSessionId;
071   private String requestURI;
072   private String servletPath = "";
073   private HttpSession httpSession = MockHttpSession.create();
074   private RestContext restContext;
075   private String uri = "";
076   private boolean debug = false;
077
078   /**
079    * Creates a new servlet request.
080    *
081    * Initialized with the following:
082    * <ul>
083    *    <li><code>"Accept: text/json+simple"</code>
084    *    <li><code>"Content-Type: text/json"</code>
085    * </ul>
086    *
087    * @return A new request.
088    */
089   public static MockServletRequest create() {
090      MockServletRequest r = new MockServletRequest();
091      return r;
092   }
093
094   /**
095    * Creates a new servlet request with the specified method name and request path.
096    *
097    * Initialized with the following:
098    * <ul>
099    *    <li><code>"Accept: text/json+simple"</code>
100    *    <li><code>"Content-Type: text/json"</code>
101    * </ul>
102    *
103    * @param method The HTTP method  name.
104    * @param path The request path.
105    * @param pathArgs Optional path arguments.
106    *
107    * @return A new request.
108    */
109   public static MockServletRequest create(String method, String path, Object...pathArgs) {
110      return create()
111         .method(method)
112         .uri(StringUtils.format(path, pathArgs));
113   }
114
115   /**
116    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/json"</js>.
117    *
118    * @return This object (for method chaining).
119    */
120   public MockServletRequest json() {
121      return header("Accept", "application/json").header("Content-Type", "application/json");
122   }
123
124   /**
125    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/xml"</js>.
126    *
127    * @return This object (for method chaining).
128    */
129   public MockServletRequest xml() {
130      return header("Accept", "text/xml").header("Content-Type", "text/xml");
131   }
132
133   /**
134    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/html"</js>.
135    *
136    * @return This object (for method chaining).
137    */
138   public MockServletRequest html() {
139      return header("Accept", "text/html").header("Content-Type", "text/html");
140   }
141
142   /**
143    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/plain"</js>.
144    *
145    * @return This object (for method chaining).
146    */
147   public MockServletRequest plainText() {
148      return header("Accept", "text/plain").header("Content-Type", "text/plain");
149   }
150
151   /**
152    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
153    *
154    * @return This object (for method chaining).
155    */
156   public MockServletRequest msgpack() {
157      return header("Accept", "octal/msgpack").header("Content-Type", "octal/msgpack");
158   }
159
160   /**
161    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/uon"</js>.
162    *
163    * @return This object (for method chaining).
164    */
165   public MockServletRequest uon() {
166      return header("Accept", "text/uon").header("Content-Type", "text/uon");
167   }
168
169   /**
170    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"application/x-www-form-urlencoded"</js>.
171    *
172    * @return This object (for method chaining).
173    */
174   public MockServletRequest urlEnc() {
175      return header("Accept", "application/x-www-form-urlencoded").header("Content-Type", "application/x-www-form-urlencoded");
176   }
177
178   /**
179    * Convenience method for setting <code>Accept</code> and <code>Content-Type</code> headers to <js>"text/yaml"</js>.
180    *
181    * @return This object (for method chaining).
182    */
183   public MockServletRequest yaml() {
184      return header("Accept", "text/yaml").header("Content-Type", "text/yaml");
185   }
186
187   /**
188    * Fluent setter.
189    *
190    * @param uri The URI of the request.
191    * @return This object (for method chaining).
192    */
193   @Override /* MockHttpRequest */
194   public MockServletRequest uri(String uri) {
195      this.uri = emptyIfNull(uri);
196      return this;
197   }
198
199   /**
200    * Fluent setter.
201    *
202    * @param restContext The rest context.
203    * @return This object (for method chaining).
204    */
205   public MockServletRequest restContext(RestContext restContext) {
206      this.restContext = restContext;
207      return this;
208   }
209
210   /**
211    * Executes this request and returns the response object.
212    *
213    * @return The response object.
214    * @throws Exception
215    */
216   @Override /* MockHttpRequest */
217   public MockServletResponse execute() throws Exception {
218      MockServletResponse res = MockServletResponse.create();
219      restContext.getCallHandler().service(this, res);
220
221      // If the status isn't set, something's broken.
222      if (res.getStatus() == 0)
223         throw new RuntimeException("Response status was 0.");
224
225      if (debug)
226         log(this, res);
227
228      return res;
229   }
230
231   private void log(MockServletRequest req, MockServletResponse res) {
232      StringBuilder sb = new StringBuilder();
233      sb.append("\n=== HTTP Call =================================================================");
234
235      sb.append("\n=== REQUEST ===");
236      sb.append("\nTODO");
237      sb.append("\n=== RESPONSE ===");
238      sb.append("\nStatus: ").append(res.getStatus());
239      sb.append("\n---response headers---");
240      for (Map.Entry<String,String[]> h : res.getHeaders().entrySet())
241         for (String h2 : h.getValue())
242            sb.append("\n").append(h.getKey()).append(": ").append(h2);
243      sb.append("\n---response content---\n");
244      sb.append(res.getBodyAsString());
245      sb.append("\n=== END ========================================================================");
246
247      System.err.println(sb);  // NOT DEBUG
248   }
249
250   /**
251    * Fluent setter.
252    *
253    * @param value The method name for this request.
254    * @return This object (for method chaining).
255    */
256   @Override /* MockHttpRequest */
257   public MockServletRequest method(String value) {
258      this.method = value;
259      return this;
260   }
261
262   /**
263    * Fluent setter.
264    *
265    * @param value The character encoding.
266    * @return This object (for method chaining).
267    */
268   public MockServletRequest characterEncoding(String value) {
269      this.characterEncoding = value;
270      return this;
271   }
272
273   /**
274    * Fluent setter.
275    *
276    * @param value The protocol.
277    * @return This object (for method chaining).
278    */
279   public MockServletRequest protocol(String value) {
280      this.protocol = value;
281      return this;
282   }
283
284   /**
285    * Fluent setter.
286    *
287    * @param value The scheme.
288    * @return This object (for method chaining).
289    */
290   public MockServletRequest scheme(String value) {
291      this.scheme = value;
292      return this;
293   }
294
295   /**
296    * Fluent setter.
297    *
298    * @param value The server name.
299    * @return This object (for method chaining).
300    */
301   public MockServletRequest serverName(String value) {
302      this.serverName = value;
303      return this;
304   }
305
306   /**
307    * Fluent setter.
308    *
309    * @param value The server port.
310    * @return This object (for method chaining).
311    */
312   public MockServletRequest serverPort(int value) {
313      this.serverPort = value;
314      return this;
315   }
316
317   /**
318    * Fluent setter.
319    *
320    * @param value The remote address.
321    * @return This object (for method chaining).
322    */
323   public MockServletRequest remoteAddr(String value) {
324      this.remoteAddr = value;
325      return this;
326   }
327
328   /**
329    * Fluent setter.
330    *
331    * @param value The remote port.
332    * @return This object (for method chaining).
333    */
334   public MockServletRequest remoteHost(String value) {
335      this.remoteHost = value;
336      return this;
337   }
338
339   /**
340    * Fluent setter.
341    *
342    * @param value The locale.
343    * @return This object (for method chaining).
344    */
345   public MockServletRequest locale(Locale value) {
346      this.locale = value;
347      return this;
348   }
349
350   /**
351    * Fluent setter.
352    *
353    * @param value The real path.
354    * @return This object (for method chaining).
355    */
356   public MockServletRequest realPath(String value) {
357      this.realPath = value;
358      return this;
359   }
360
361   /**
362    * Fluent setter.
363    *
364    * @param value The remote port.
365    * @return This object (for method chaining).
366    */
367   public MockServletRequest remotePort(int value) {
368      this.remotePort = value;
369      return this;
370   }
371
372   /**
373    * Fluent setter.
374    *
375    * @param value The local name.
376    * @return This object (for method chaining).
377    */
378   public MockServletRequest localName(String value) {
379      this.localName = value;
380      return this;
381   }
382
383   /**
384    * Fluent setter.
385    *
386    * @param value The local address.
387    * @return This object (for method chaining).
388    */
389   public MockServletRequest localAddr(String value) {
390      this.localAddr = value;
391      return this;
392   }
393
394   /**
395    * Fluent setter.
396    *
397    * @param value The local port.
398    * @return This object (for method chaining).
399    */
400   public MockServletRequest localPort(int value) {
401      this.localPort = value;
402      return this;
403   }
404
405   /**
406    * Fluent setter.
407    *
408    * @param value The request dispatcher.
409    * @return This object (for method chaining).
410    */
411   public MockServletRequest requestDispatcher(RequestDispatcher value) {
412      this.requestDispatcher = value;
413      return this;
414   }
415
416   /**
417    * Fluent setter.
418    *
419    * @param value The servlet context.
420    * @return This object (for method chaining).
421    */
422   public MockServletRequest servletContext(ServletContext value) {
423      this.servletContext = value;
424      return this;
425   }
426
427   /**
428    * Fluent setter.
429    *
430    * @param value The dispatcher type.
431    * @return This object (for method chaining).
432    */
433   public MockServletRequest dispatcherType(DispatcherType value) {
434      this.dispatcherType = value;
435      return this;
436   }
437
438   /**
439    * Fluent setter.
440    *
441    * @param value The auth type.
442    * @return This object (for method chaining).
443    */
444   public MockServletRequest authType(String value) {
445      this.authType = value;
446      return this;
447   }
448
449   /**
450    * Fluent setter.
451    *
452    * @param value The cookies.
453    * @return This object (for method chaining).
454    */
455   public MockServletRequest cookies(Cookie[] value) {
456      this.cookies = value;
457      return this;
458   }
459
460   /**
461    * Fluent setter.
462    *
463    * @param value The path info.
464    * @return This object (for method chaining).
465    */
466   public MockServletRequest pathInfo(String value) {
467      this.pathInfo = value;
468      return this;
469   }
470
471   /**
472    * Fluent setter.
473    *
474    * @param value The path translated.
475    * @return This object (for method chaining).
476    */
477   public MockServletRequest pathTranslated(String value) {
478      this.pathTranslated = value;
479      return this;
480   }
481
482   /**
483    * Fluent setter.
484    *
485    * @param value The context path.
486    * @return This object (for method chaining).
487    */
488   public MockServletRequest contextPath(String value) {
489      this.contextPath = value;
490      return this;
491   }
492
493   /**
494    * Fluent setter.
495    *
496    * @param value The query string.
497    * @return This object (for method chaining).
498    */
499   public MockServletRequest queryString(String value) {
500      this.queryString = value;
501      return this;
502   }
503
504   /**
505    * Fluent setter.
506    *
507    * @param value The remote user.
508    * @return This object (for method chaining).
509    */
510   public MockServletRequest remoteUser(String value) {
511      this.remoteUser = value;
512      return this;
513   }
514
515   /**
516    * Fluent setter.
517    *
518    * @param value The user principal.
519    * @return This object (for method chaining).
520    */
521   public MockServletRequest userPrincipal(Principal value) {
522      this.userPrincipal = value;
523      return this;
524   }
525
526   /**
527    * Fluent setter.
528    *
529    * @param value The requested session ID.
530    * @return This object (for method chaining).
531    */
532   public MockServletRequest requestedSessionId(String value) {
533      this.requestedSessionId = value;
534      return this;
535   }
536
537   /**
538    * Fluent setter.
539    *
540    * @param value The request URI.
541    * @return This object (for method chaining).
542    */
543   public MockServletRequest requestURI(String value) {
544      this.requestURI = value;
545      return this;
546   }
547
548   /**
549    * Fluent setter.
550    *
551    * @param value The servlet path.
552    * @return This object (for method chaining).
553    */
554   public MockServletRequest servletPath(String value) {
555      this.servletPath = value;
556      return this;
557   }
558
559   /**
560    * Fluent setter.
561    *
562    * @param value The HTTP session.
563    * @return This object (for method chaining).
564    */
565   public MockServletRequest httpSession(HttpSession value) {
566      this.httpSession = value;
567      return this;
568   }
569
570   @Override /* HttpServletRequest */
571   public Object getAttribute(String name) {
572      return attributeMap.get(name);
573   }
574
575   @Override /* HttpServletRequest */
576   public Enumeration<String> getAttributeNames() {
577      return Collections.enumeration(attributeMap.keySet());
578   }
579
580   @Override /* HttpServletRequest */
581   public String getCharacterEncoding() {
582      return characterEncoding;
583   }
584
585   @Override /* HttpServletRequest */
586   public void setCharacterEncoding(String characterEncoding) throws UnsupportedEncodingException {
587      this.characterEncoding = characterEncoding;
588   }
589
590   @Override /* HttpServletRequest */
591   public int getContentLength() {
592      return body == null ? 0 : body.length;
593   }
594
595   @Override /* HttpServletRequest */
596   public long getContentLengthLong() {
597      return body == null ? 0 : body.length;
598   }
599
600   @Override /* HttpServletRequest */
601   public String getContentType() {
602      return getHeader("Content-Type");
603   }
604
605   @Override /* HttpServletRequest */
606   public ServletInputStream getInputStream() throws IOException {
607      if (formDataMap != null)
608         body = UrlEncodingSerializer.DEFAULT.toString(formDataMap).getBytes();
609      return new BoundedServletInputStream(new ByteArrayInputStream(body), Integer.MAX_VALUE);
610   }
611
612   @Override /* HttpServletRequest */
613   public String getParameter(String name) {
614      String[] s = getParameterMap().get(name);
615      return s == null || s.length == 0 ? null : s[0];
616   }
617
618   @Override /* HttpServletRequest */
619   public Enumeration<String> getParameterNames() {
620      return Collections.enumeration(new ArrayList<>(getParameterMap().keySet()));
621   }
622
623   @Override /* HttpServletRequest */
624   public String[] getParameterValues(String name) {
625      return getParameterMap().get(name);
626   }
627
628   @Override /* HttpServletRequest */
629   public Map<String,String[]> getParameterMap() {
630      if (queryData == null) {
631         try {
632            if ("POST".equalsIgnoreCase(method)) {
633               if (formDataMap != null)
634                  queryData = formDataMap;
635               else
636                  queryData = RestUtils.parseQuery(IOUtils.read(body));
637            } else {
638               queryData = RestUtils.parseQuery(getQueryString());
639            }
640         } catch (Exception e) {
641            throw new RuntimeException(e);
642         }
643      }
644      return queryData;
645   }
646
647   @Override /* HttpServletRequest */
648   public String getProtocol() {
649      return protocol;
650   }
651
652   @Override /* HttpServletRequest */
653   public String getScheme() {
654      return scheme;
655   }
656
657   @Override /* HttpServletRequest */
658   public String getServerName() {
659      return serverName;
660   }
661
662   @Override /* HttpServletRequest */
663   public int getServerPort() {
664      return serverPort;
665   }
666
667   @Override /* HttpServletRequest */
668   public BufferedReader getReader() throws IOException {
669      return new BufferedReader(new InputStreamReader(getInputStream(), characterEncoding));
670   }
671
672   @Override /* HttpServletRequest */
673   public String getRemoteAddr() {
674      return remoteAddr;
675   }
676
677   @Override /* HttpServletRequest */
678   public String getRemoteHost() {
679      return remoteHost;
680   }
681
682   @Override /* HttpServletRequest */
683   public void setAttribute(String name, Object o) {
684      this.attributeMap.put(name, o);
685   }
686
687   @Override /* HttpServletRequest */
688   public void removeAttribute(String name) {
689      this.attributeMap.remove(name);
690   }
691
692   @Override /* HttpServletRequest */
693   public Locale getLocale() {
694      return locale;
695   }
696
697   @Override /* HttpServletRequest */
698   public Enumeration<Locale> getLocales() {
699      return Collections.enumeration(Arrays.asList(locale));
700   }
701
702   @Override /* HttpServletRequest */
703   public boolean isSecure() {
704      return false;
705   }
706
707   @Override /* HttpServletRequest */
708   public RequestDispatcher getRequestDispatcher(String path) {
709      return requestDispatcher;
710   }
711
712   @Override /* HttpServletRequest */
713   public String getRealPath(String path) {
714      return realPath;
715   }
716
717   @Override /* HttpServletRequest */
718   public int getRemotePort() {
719      return remotePort;
720   }
721
722   @Override /* HttpServletRequest */
723   public String getLocalName() {
724      return localName;
725   }
726
727   @Override /* HttpServletRequest */
728   public String getLocalAddr() {
729      return localAddr;
730   }
731
732   @Override /* HttpServletRequest */
733   public int getLocalPort() {
734      return localPort;
735   }
736
737   @Override /* HttpServletRequest */
738   public ServletContext getServletContext() {
739      return servletContext;
740   }
741
742   @Override /* HttpServletRequest */
743   public AsyncContext startAsync() throws IllegalStateException {
744      return null;
745   }
746
747   @Override /* HttpServletRequest */
748   public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
749      return null;
750   }
751
752   @Override /* HttpServletRequest */
753   public boolean isAsyncStarted() {
754      return false;
755   }
756
757   @Override /* HttpServletRequest */
758   public boolean isAsyncSupported() {
759      return false;
760   }
761
762   @Override /* HttpServletRequest */
763   public AsyncContext getAsyncContext() {
764      return null;
765   }
766
767   @Override /* HttpServletRequest */
768   public DispatcherType getDispatcherType() {
769      return dispatcherType;
770   }
771
772   @Override /* HttpServletRequest */
773   public String getAuthType() {
774      return authType;
775   }
776
777   @Override /* HttpServletRequest */
778   public Cookie[] getCookies() {
779      return cookies;
780   }
781
782   @Override /* HttpServletRequest */
783   public long getDateHeader(String name) {
784      String s = getHeader(name);
785      return s == null ? 0 : org.apache.juneau.http.Date.forString(s).asDate().getTime();
786   }
787
788   @Override /* HttpServletRequest */
789   public String getHeader(String name) {
790      String[] s = headerMap.get(name);
791      return s == null || s.length == 0 ? null : s[0];
792   }
793
794   @Override /* HttpServletRequest */
795   public Enumeration<String> getHeaders(String name) {
796      String[] s = headerMap.get(name);
797      return Collections.enumeration(Arrays.asList(s == null ? new String[0] : s));
798   }
799
800   @Override /* HttpServletRequest */
801   public Enumeration<String> getHeaderNames() {
802      return Collections.enumeration(headerMap.keySet());
803   }
804
805   @Override /* HttpServletRequest */
806   public int getIntHeader(String name) {
807      String s = getHeader(name);
808      return s == null || s.isEmpty() ? 0 : Integer.parseInt(s);
809   }
810
811   @Override /* HttpServletRequest */
812   public String getMethod() {
813      return method;
814   }
815
816   @Override /* HttpServletRequest */
817   public String getPathInfo() {
818      if (pathInfo == null) {
819         pathInfo = getRequestURI();
820         if (isNotEmpty(contextPath))
821            pathInfo = pathInfo.substring(contextPath.length());
822         if (isNotEmpty(servletPath))
823            pathInfo = pathInfo.substring(servletPath.length());
824      }
825      return nullIfEmpty(urlDecode(pathInfo));
826   }
827
828   @Override /* HttpServletRequest */
829   public String getPathTranslated() {
830      if (pathTranslated == null)
831         pathTranslated = "/mock-path" + getPathInfo();
832      return pathTranslated;
833   }
834
835   @Override /* HttpServletRequest */
836   public String getContextPath() {
837      return contextPath;
838   }
839
840   @Override /* HttpServletRequest */
841   public String getQueryString() {
842      if (queryString == null) {
843         queryString = "";
844         if (uri.indexOf('?') != -1) {
845            queryString = uri.substring(uri.indexOf('?') + 1);
846         if (queryString.indexOf('#') != -1)
847            queryString = queryString.substring(0, queryString.indexOf('#'));
848         }
849      }
850      return isEmpty(queryString) ? null : queryString;
851   }
852
853   @Override /* HttpServletRequest */
854   public String getRemoteUser() {
855      return remoteUser;
856   }
857
858   @Override /* HttpServletRequest */
859   public boolean isUserInRole(String role) {
860      return false;
861   }
862
863   @Override /* HttpServletRequest */
864   public Principal getUserPrincipal() {
865      return userPrincipal;
866   }
867
868   @Override /* HttpServletRequest */
869   public String getRequestedSessionId() {
870      return requestedSessionId;
871   }
872
873   @Override /* HttpServletRequest */
874   public String getRequestURI() {
875      if (requestURI == null) {
876         requestURI = uri;
877         requestURI = requestURI.replaceAll("^\\w+\\:\\/\\/[^\\/]+", "").replaceAll("\\?.*$", "");
878      }
879      return requestURI;
880   }
881
882   @Override /* HttpServletRequest */
883   public StringBuffer getRequestURL() {
884      return new StringBuffer(uri.replaceAll("\\?.*$", ""));
885   }
886
887   @Override /* HttpServletRequest */
888   public String getServletPath() {
889      return servletPath;
890   }
891
892   @Override /* HttpServletRequest */
893   public HttpSession getSession(boolean create) {
894      return httpSession;
895   }
896
897   @Override /* HttpServletRequest */
898   public HttpSession getSession() {
899      return httpSession;
900   }
901
902   @Override /* HttpServletRequest */
903   public String changeSessionId() {
904      return null;
905   }
906
907   @Override /* HttpServletRequest */
908   public boolean isRequestedSessionIdValid() {
909      return false;
910   }
911
912   @Override /* HttpServletRequest */
913   public boolean isRequestedSessionIdFromCookie() {
914      return false;
915   }
916
917   @Override /* HttpServletRequest */
918   public boolean isRequestedSessionIdFromURL() {
919      return false;
920   }
921
922   @Override /* HttpServletRequest */
923   public boolean isRequestedSessionIdFromUrl() {
924      return false;
925   }
926
927   @Override /* HttpServletRequest */
928   public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
929      return false;
930   }
931
932   @Override /* HttpServletRequest */
933   public void login(String username, String password) throws ServletException {
934   }
935
936   @Override /* HttpServletRequest */
937   public void logout() throws ServletException {
938   }
939
940   @Override /* HttpServletRequest */
941   public Collection<Part> getParts() throws IOException, ServletException {
942      return null;
943   }
944
945   @Override /* HttpServletRequest */
946   public Part getPart(String name) throws IOException, ServletException {
947      return null;
948   }
949
950   @Override /* HttpServletRequest */
951   public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
952      return null;
953   }
954
955   //=================================================================================================================
956   // Convenience methods
957   //=================================================================================================================
958
959   /**
960    * Fluent setter.
961    *
962    * @param name Header name.
963    * @param value
964    *    Header value.
965    *    <br>The value is converted to a simple string using {@link Object#toString()}.
966    * @return This object (for method chaining).
967    */
968   @Override /* MockHttpRequest */
969   public MockServletRequest header(String name, Object value) {
970      this.headerMap.put(name, new String[] {asString(value)});
971      return this;
972   }
973
974   /**
975    * Fluent setter.
976    *
977    * @param name Request attribute name.
978    * @param value Request attribute value.
979    * @return This object (for method chaining).
980    */
981   public MockServletRequest attribute(String name, Object value) {
982      this.attributeMap.put(name, value);
983      return this;
984   }
985
986   /**
987    * Fluent setter.
988    *
989    * @param value
990    *    The body of the request.
991    *    <br>Can be any of the following data types:
992    *    <ul>
993    *       <li><code><jk>byte</jk>[]</code>
994    *       <li>{@link Reader}
995    *       <li>{@link InputStream}
996    *       <li>{@link CharSequence}
997    *    </ul>
998    * @return This object (for method chaining).
999    */
1000   @Override /* MockHttpRequest */
1001   public MockServletRequest body(Object value) {
1002      try {
1003         if (value instanceof byte[])
1004            this.body = (byte[])value;
1005         if (value instanceof Reader)
1006            this.body = IOUtils.read((Reader)value).getBytes();
1007         if (value instanceof InputStream)
1008            this.body = IOUtils.readBytes((InputStream)value, 1024);
1009         if (value instanceof CharSequence)
1010            this.body = ((CharSequence)value).toString().getBytes();
1011      } catch (IOException e) {
1012         throw new RuntimeException(e);
1013      }
1014      return this;
1015   }
1016
1017   /**
1018    * Adds a form data entry to this request.
1019    *
1020    * @param key The form data key.
1021    * @param value The form data value.
1022    *    <br>The value is converted to a simple string using {@link Object#toString()}.
1023    * @return This object (for method chaining).
1024    */
1025   public MockServletRequest formData(String key, Object value) {
1026      if (formDataMap == null)
1027         formDataMap = new LinkedHashMap<>();
1028      String s = asString(value);
1029      String[] existing = formDataMap.get(key);
1030      if (existing == null)
1031         existing = new String[]{s};
1032      else
1033         existing = new AList<>().appendAll(Arrays.asList(existing)).append(s).toArray(new String[0]);
1034      formDataMap.put(key, existing);
1035      return this;
1036   }
1037
1038   /**
1039    * Adds a query data entry to this request.
1040    *
1041    * @param key The query key.
1042    * @param value The query value.
1043    *    <br>The value is converted to a simple string using {@link Object#toString()}.
1044    * @return This object (for method chaining).
1045    */
1046   public MockServletRequest query(String key, Object value) {
1047      if (queryData == null)
1048         queryData = new LinkedHashMap<>();
1049      String s = asString(value);
1050      String[] existing = queryData.get(key);
1051      if (existing == null)
1052         existing = new String[]{s};
1053      else
1054         existing = new AList<>().appendAll(Arrays.asList(existing)).append(s).toArray(new String[0]);
1055      queryData.put(key, existing);
1056      return this;
1057   }
1058
1059   //=================================================================================================================
1060   // Convenience methods - headers
1061   //=================================================================================================================
1062
1063   /**
1064    * Specifies the <code>Accept</code> header value on the request.
1065    *
1066    * @param value The new value.
1067    * @return This object (for method chaining).
1068    */
1069   public MockServletRequest accept(Object value) {
1070      return header("Accept", value);
1071   }
1072
1073   /**
1074    * Specifies the <code>Accept-Charset</code> header value on the request.
1075    *
1076    * @param value The new value.
1077    * @return This object (for method chaining).
1078    */
1079   public MockServletRequest acceptCharset(Object value) {
1080      return header("Accept-Charset", value);
1081   }
1082
1083   /**
1084    * Specifies the <code>Accept-Encoding</code> header value on the request.
1085    *
1086    * @param value The new value.
1087    * @return This object (for method chaining).
1088    */
1089   public MockServletRequest acceptEncoding(Object value) {
1090      return header("Accept-Encoding", value);
1091   }
1092
1093   /**
1094    * Specifies the <code>Accept-Language</code> header value on the request.
1095    *
1096    * @param value The new value.
1097    * @return This object (for method chaining).
1098    */
1099   public MockServletRequest acceptLanguage(Object value) {
1100      return header("Accept-Language", value);
1101   }
1102
1103   /**
1104    * Specifies the <code>Authorization</code> header value on the request.
1105    *
1106    * @param value The new value for the header.
1107    * @return This object (for method chaining).
1108    */
1109   public MockServletRequest authorization(Object value) {
1110      return header("Authorization", value);
1111   }
1112
1113   /**
1114    * Specifies the <code>Cache-Control</code> header value on the request.
1115    *
1116    * @param value The new value for the header.
1117    * @return This object (for method chaining).
1118    */
1119   public MockServletRequest cacheControl(Object value) {
1120      return header("Cache-Control", value);
1121   }
1122
1123   /**
1124    * Specifies the <code>X-Client-Version</code> header value on the request.
1125    *
1126    * @param value The new value.
1127    * @return This object (for method chaining).
1128    */
1129   public MockServletRequest clientVersion(Object value) {
1130      return header("X-Client-Version", value);
1131   }
1132
1133   /**
1134    * Specifies the <code>Connection</code> header value on the request.
1135    *
1136    * @param value The new value for the header.
1137    * @return This object (for method chaining).
1138    */
1139   public MockServletRequest connection(Object value) {
1140      return header("Connection", value);
1141   }
1142
1143   /**
1144    * Specifies the <code>Content-Encoding</code> header value on the request.
1145    *
1146    * @param value The new value.
1147    * @return This object (for method chaining).
1148    */
1149   public MockServletRequest contentEncoding(Object value) {
1150      return header("Content-Encoding", value);
1151   }
1152
1153   /**
1154    * Specifies the <code>Content-Length</code> header value on the request.
1155    *
1156    * @param value The new value for the header.
1157    * @return This object (for method chaining).
1158    */
1159   public MockServletRequest contentLength(Object value) {
1160      return header("Content-Length", value);
1161   }
1162
1163   /**
1164    * Specifies the <code>Content-Type</code> header value on the request.
1165    *
1166    * @param value The new value.
1167    * @return This object (for method chaining).
1168    */
1169   public MockServletRequest contentType(Object value) {
1170      return header("Content-Type", value);
1171   }
1172
1173   /**
1174    * Specifies the <code>Date</code> header value on the request.
1175    *
1176    * @param value The new value for the header.
1177    * @return This object (for method chaining).
1178    */
1179   public MockServletRequest date(Object value) {
1180      return header("Date", value);
1181   }
1182
1183   /**
1184    * Specifies the <code>Expect</code> header value on the request.
1185    *
1186    * @param value The new value for the header.
1187    * @return This object (for method chaining).
1188    */
1189   public MockServletRequest expect(Object value) {
1190      return header("Expect", value);
1191   }
1192
1193   /**
1194    * Specifies the <code>From</code> header value on the request.
1195    *
1196    * @param value The new value for the header.
1197    * @return This object (for method chaining).
1198    */
1199   public MockServletRequest from(Object value) {
1200      return header("From", value);
1201   }
1202
1203   /**
1204    * Specifies the <code>Host</code> header value on the request.
1205    *
1206    * @param value The new value for the header.
1207    * @return This object (for method chaining).
1208    */
1209   public MockServletRequest host(Object value) {
1210      return header("Host", value);
1211   }
1212
1213   /**
1214    * Specifies the <code>If-Match</code> header value on the request.
1215    *
1216    * @param value The new value for the header.
1217    * @return This object (for method chaining).
1218    */
1219   public MockServletRequest ifMatch(Object value) {
1220      return header("If-Match", value);
1221   }
1222
1223   /**
1224    * Specifies the <code>If-Modified-Since</code> header value on the request.
1225    *
1226    * @param value The new value for the header.
1227    * @return This object (for method chaining).
1228    */
1229   public MockServletRequest ifModifiedSince(Object value) {
1230      return header("If-Modified-Since", value);
1231   }
1232
1233   /**
1234    * Specifies the <code>If-None-Match</code> header value on the request.
1235    *
1236    * @param value The new value for the header.
1237    * @return This object (for method chaining).
1238    */
1239   public MockServletRequest ifNoneMatch(Object value) {
1240      return header("If-None-Match", value);
1241   }
1242
1243   /**
1244    * Specifies the <code>If-Range</code> header value on the request.
1245    *
1246    * @param value The new value for the header.
1247    * @return This object (for method chaining).
1248    */
1249   public MockServletRequest ifRange(Object value) {
1250      return header("If-Range", value);
1251   }
1252
1253   /**
1254    * Specifies the <code>If-Unmodified-Since</code> header value on the request.
1255    *
1256    * @param value The new value for the header.
1257    * @return This object (for method chaining).
1258    */
1259   public MockServletRequest ifUnmodifiedSince(Object value) {
1260      return header("If-Unmodified-Since", value);
1261   }
1262
1263   /**
1264    * Specifies the <code>Max-Forwards</code> header value on the request.
1265    *
1266    * @param value The new value for the header.
1267    * @return This object (for method chaining).
1268    */
1269   public MockServletRequest maxForwards(Object value) {
1270      return header("Max-Forwards", value);
1271   }
1272
1273   /**
1274    * Specifies the <code>Pragma</code> header value on the request.
1275    *
1276    * @param value The new value for the header.
1277    * @return This object (for method chaining).
1278    */
1279   public MockServletRequest pragma(Object value) {
1280      return header("Pragma", value);
1281   }
1282
1283   /**
1284    * Specifies the <code>Proxy-Authorization</code> header value on the request.
1285    *
1286    * @param value The new value for the header.
1287    * @return This object (for method chaining).
1288    */
1289   public MockServletRequest proxyAuthorization(Object value) {
1290      return header("Proxy-Authorization", value);
1291   }
1292
1293   /**
1294    * Specifies the <code>Range</code> header value on the request.
1295    *
1296    * @param value The new value for the header.
1297    * @return This object (for method chaining).
1298    */
1299   public MockServletRequest range(Object value) {
1300      return header("Range", value);
1301   }
1302
1303   /**
1304    * Specifies the <code>Referer</code> header value on the request.
1305    *
1306    * @param value The new value for the header.
1307    * @return This object (for method chaining).
1308    */
1309   public MockServletRequest referer(Object value) {
1310      return header("Referer", value);
1311   }
1312
1313   /**
1314    * Specifies the <code>TE</code> header value on the request.
1315    *
1316    * @param value The new value for the header.
1317    * @return This object (for method chaining).
1318    */
1319   public MockServletRequest te(Object value) {
1320      return header("TE", value);
1321   }
1322
1323   /**
1324    * Specifies the <code>Upgrade</code> header value on the request.
1325    *
1326    * @param value The new value for the header.
1327    * @return This object (for method chaining).
1328    */
1329   public MockServletRequest upgrade(Object value) {
1330      return header("Upgrade", value);
1331   }
1332
1333   /**
1334    * Specifies the <code>User-Agent</code> header value on the request.
1335    *
1336    * @param value The new value for the header.
1337    * @return This object (for method chaining).
1338    */
1339   public MockServletRequest userAgent(Object value) {
1340      return header("User-Agent", value);
1341   }
1342
1343   /**
1344    * Specifies the <code>Warning</code> header value on the request.
1345    *
1346    * @param value The new value for the header.
1347    * @return This object (for method chaining).
1348    */
1349   public MockServletRequest warning(Object value) {
1350      return header("Warning", value);
1351   }
1352
1353   /**
1354    * Enabled debug mode on this request.
1355    *
1356    * <p>
1357    * Causes information about the request execution to be sent to STDERR.
1358    *
1359    * @return This object (for method chaining).
1360    */
1361   public MockServletRequest debug() {
1362      this.debug = true;
1363      return this;
1364   }
1365}