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