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