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