001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.mock; 018 019import static java.util.Collections.*; 020import static org.apache.juneau.commons.utils.CollectionUtils.*; 021import static org.apache.juneau.commons.utils.IoUtils.*; 022import static org.apache.juneau.commons.utils.Shorts.*; 023import static org.apache.juneau.commons.utils.StringUtils.*; 024import static org.apache.juneau.commons.utils.StringUtils.isEmpty; 025import static org.apache.juneau.commons.utils.ThrowableUtils.*; 026import static org.apache.juneau.http.HttpHeaders.*; 027 028import java.io.*; 029import java.security.*; 030import java.util.*; 031import java.util.logging.*; 032 033import org.apache.http.*; 034import org.apache.juneau.marshall.marshaller.*; 035import org.apache.juneau.rest.server.util.*; 036 037import jakarta.servlet.*; 038import jakarta.servlet.http.*; 039 040/** 041 * A mutable implementation of {@link HttpServletRequest} for mocking purposes. 042 * 043 * <h5 class='section'>See Also:</h5><ul> 044 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestMock">juneau-rest-mock</a> 045 * </ul> 046 */ 047@SuppressWarnings({ 048 "java:S3776", // Branching is inherent to applyOverrides() and getQueryString(), which merge request parts and parameters from many sources. 049 "resource" // Streams returned to servlet container; lifecycle managed by the container 050}) 051public class MockServletRequest implements HttpServletRequest { 052 053 /** 054 * Creates a new servlet request. 055 * 056 * Initialized with the following: 057 * <ul> 058 * <li><c>"Accept: text/json5"</c> 059 * <li><c>"Content-Type: text/json"</c> 060 * </ul> 061 * 062 * @return A new request. 063 */ 064 public static MockServletRequest create() { 065 return new MockServletRequest(); 066 } 067 068 /** 069 * Creates a new servlet request with the specified method name and request path. 070 * 071 * Initialized with the following: 072 * <ul> 073 * <li><c>"Accept: text/json5"</c> 074 * <li><c>"Content-Type: text/json"</c> 075 * </ul> 076 * 077 * @param method The HTTP method name. 078 * @param uri The request path. 079 * @param pathArgs Optional path arguments. 080 * 081 * @return A new request. 082 */ 083 public static MockServletRequest create(String method, String uri, Object...pathArgs) { 084 return create().method(method).uri(f(uri, pathArgs)); 085 } 086 087 private String method = "GET"; 088 private final Map<String,String[]> queryDataMap = map(); 089 private Map<String,String[]> formDataMap; 090 private final Map<String,String[]> headerMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 091 private final Map<String,Object> attributeMap = map(); 092 private String characterEncoding = "UTF-8"; 093 private byte[] content = {}; 094 private String protocol = "HTTP/1.1"; 095 private String scheme = "http"; 096 private String serverName = "localhost"; 097 private int serverPort = 8080; 098 private String remoteAddr = ""; 099 private String remoteHost = ""; 100 private Locale locale = Locale.ENGLISH; 101 private int remotePort; 102 private String localName; 103 private String localAddr; 104 private int localPort; 105 private final Map<String,RequestDispatcher> requestDispatcher = map(); 106 private ServletContext servletContext; 107 private DispatcherType dispatcherType; 108 private String authType; 109 private Cookie[] cookies; 110 private String pathInfo; 111 private String pathTranslated; 112 private String contextPath = ""; 113 private String queryString; 114 private String remoteUser; 115 private Principal userPrincipal; 116 private String requestedSessionId; 117 private String requestURI; 118 private String servletPath = ""; 119 private HttpSession httpSession = MockHttpSession.create(); 120 121 private String uri = ""; 122 123 private Set<String> roles = set(); 124 125 private Level logLevel; 126 127 /** 128 * If the specified request is a 129 * {@link org.apache.juneau.rest.mock.classic.MockRestRequest}, applies any of the override values 130 * to this servlet request. 131 * 132 * @param req The request to copy overrides from. 133 * @return This object. 134 */ 135 public MockServletRequest applyOverrides(HttpRequest req) { 136 137 if (req instanceof org.apache.juneau.rest.mock.classic.MockRestRequest req2) { 138 req2.getAttributeMap().forEach(this::attribute); 139 req2.getRequestDispatcherMap().forEach(this::requestDispatcher); 140 if (nn(req2.getCharacterEncoding())) 141 characterEncoding(req2.getCharacterEncoding()); 142 if (nn(req2.getProtocol())) 143 protocol(req2.getProtocol()); 144 if (nn(req2.getScheme())) 145 scheme(req2.getScheme()); 146 if (nn(req2.getServerName())) 147 serverName(req2.getServerName()); 148 if (nn(req2.getRemoteAddr())) 149 remoteAddr(req2.getRemoteAddr()); 150 if (nn(req2.getRemoteHost())) 151 remoteHost(req2.getRemoteHost()); 152 if (nn(req2.getLocalName())) 153 localName(req2.getLocalName()); 154 if (nn(req2.getLocalAddr())) 155 localAddr(req2.getLocalAddr()); 156 if (nn(req2.getPathInfo())) 157 pathInfo(req2.getPathInfo()); 158 if (nn(req2.getPathTranslated())) 159 pathTranslated(req2.getPathTranslated()); 160 if (nn(req2.getContextPath())) 161 contextPath(req2.getContextPath()); 162 if (nn(req2.getQueryString())) 163 queryString(req2.getQueryString()); 164 if (nn(req2.getRemoteUser())) 165 remoteUser(req2.getRemoteUser()); 166 if (nn(req2.getRequestedSessionId())) 167 requestedSessionId(req2.getRequestedSessionId()); 168 if (nn(req2.getRequestURI())) 169 requestURI(req2.getRequestURI()); 170 if (nn(req2.getServletPath())) 171 servletPath(req2.getServletPath()); 172 if (nn(req2.getAuthType())) 173 authType(req2.getAuthType()); 174 if (nn(req2.getServerPort())) 175 serverPort(req2.getServerPort()); 176 if (nn(req2.getRemotePort())) 177 remotePort(req2.getRemotePort()); 178 if (nn(req2.getLocalPort())) 179 localPort(req2.getLocalPort()); 180 if (nn(req2.getLocale())) 181 locale(req2.getLocale()); 182 if (nn(req2.getServletContext())) 183 servletContext(req2.getServletContext()); 184 if (nn(req2.getDispatcherType())) 185 dispatcherType(req2.getDispatcherType()); 186 if (nn(req2.getCookies())) 187 cookies(req2.getCookies()); 188 if (nn(req2.getUserPrincipal())) 189 userPrincipal(req2.getUserPrincipal()); 190 if (nn(req2.getHttpSession())) 191 httpSession(req2.getHttpSession()); 192 if (nn(req2.getRoles())) 193 roles(req2.getRoles()); 194 } 195 196 return this; 197 } 198 199 /** 200 * Fluent setter. 201 * 202 * @param name Request attribute name. 203 * @param value Request attribute value. 204 * @return This object. 205 */ 206 public MockServletRequest attribute(String name, Object value) { 207 this.attributeMap.put(name, value); 208 return this; 209 } 210 211 @Override /* Overridden from HttpServletRequest */ 212 public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { 213 return false; 214 } 215 216 /** 217 * Fluent setter. 218 * 219 * @param value The auth type. 220 * @return This object. 221 */ 222 public MockServletRequest authType(String value) { 223 authType = value; 224 return this; 225 } 226 227 @Override /* Overridden from HttpServletRequest */ 228 public String changeSessionId() { 229 return null; 230 } 231 232 /** 233 * Fluent setter. 234 * 235 * @param value The character encoding. 236 * @return This object. 237 */ 238 public MockServletRequest characterEncoding(String value) { 239 characterEncoding = value; 240 return this; 241 } 242 243 /** 244 * Fluent setter. 245 * 246 * @param value 247 * The body of the request. 248 * <br>Can be any of the following data types: 249 * <ul> 250 * <li><code><jk>byte</jk>[]</code> 251 * <li>{@link Reader} 252 * <li>{@link InputStream} 253 * <li>{@link CharSequence} 254 * </ul> 255 * Any other types are converted to a string using the <c>toString()</c> method. 256 * @return This object. 257 */ 258 public MockServletRequest content(Object value) { 259 try { 260 if (value instanceof byte[] value2) 261 this.content = value2; 262 else if (value instanceof Reader value2) 263 this.content = readBytes(value2); 264 else if (value instanceof InputStream value2) 265 this.content = readBytes(value2); 266 else if (value instanceof CharSequence value2) 267 this.content = value2.toString().getBytes(); 268 else if (nn(value)) 269 this.content = value.toString().getBytes(); 270 } catch (IOException e) { 271 throw toRex(e); 272 } 273 return this; 274 } 275 276 /** 277 * Fluent setter. 278 * 279 * @param value The context path. 280 * @return This object. 281 */ 282 public MockServletRequest contextPath(String value) { 283 contextPath = value; 284 return this; 285 } 286 287 /** 288 * Fluent setter. 289 * 290 * @param value The cookies. 291 * @return This object. 292 */ 293 public MockServletRequest cookies(Cookie[] value) { 294 cookies = value; 295 return this; 296 } 297 298 /** 299 * Fluent setter. 300 * 301 * @param value The dispatcher type. 302 * @return This object. 303 */ 304 public MockServletRequest dispatcherType(DispatcherType value) { 305 dispatcherType = value; 306 return this; 307 } 308 309 @Override /* Overridden from HttpServletRequest */ 310 public AsyncContext getAsyncContext() { return null; } 311 312 @Override /* Overridden from HttpServletRequest */ 313 public Object getAttribute(String name) { 314 return attributeMap.get(name); 315 } 316 317 @Override /* Overridden from HttpServletRequest */ 318 public Enumeration<String> getAttributeNames() { return Collections.enumeration(attributeMap.keySet()); } 319 320 @Override /* Overridden from HttpServletRequest */ 321 public String getAuthType() { return authType; } 322 323 @Override /* Overridden from HttpServletRequest */ 324 public String getCharacterEncoding() { return characterEncoding; } 325 326 @Override /* Overridden from HttpServletRequest */ 327 public int getContentLength() { return content == null ? 0 : content.length; } 328 329 @Override /* Overridden from HttpServletRequest */ 330 public long getContentLengthLong() { return content == null ? 0 : content.length; } 331 332 @Override /* Overridden from HttpServletRequest */ 333 public String getContentType() { return getHeader("Content-Type"); } 334 335 @Override /* Overridden from HttpServletRequest */ 336 public String getContextPath() { return contextPath; } 337 338 @Override /* Overridden from HttpServletRequest */ 339 public Cookie[] getCookies() { return cookies; } 340 341 @Override /* Overridden from HttpServletRequest */ 342 public long getDateHeader(String name) { 343 var s = getHeader(name); 344 if (s == null) 345 return 0; 346 var zonedDateTimeOpt = date(s).asZonedDateTime(); 347 return zonedDateTimeOpt.isPresent() ? zonedDateTimeOpt.get().toInstant().toEpochMilli() : 0; 348 } 349 350 @Override /* Overridden from HttpServletRequest */ 351 public DispatcherType getDispatcherType() { return dispatcherType; } 352 353 @Override /* Overridden from HttpServletRequest */ 354 public String getHeader(String name) { 355 var s = headerMap.get(name); 356 return s == null || s.length == 0 ? null : s[0]; 357 } 358 359 @Override /* Overridden from HttpServletRequest */ 360 public Enumeration<String> getHeaderNames() { return Collections.enumeration(headerMap.keySet()); } 361 362 @Override /* Overridden from HttpServletRequest */ 363 public Enumeration<String> getHeaders(String name) { 364 var s = headerMap.get(name); 365 return Collections.enumeration(l(s == null ? new String[0] : s)); 366 } 367 368 @Override /* Overridden from HttpServletRequest */ 369 public ServletInputStream getInputStream() throws IOException { 370 if (nn(formDataMap)) 371 content = UrlEncoding.of(formDataMap).getBytes(); 372 return new BoundedServletInputStream(new ByteArrayInputStream(content), Integer.MAX_VALUE); 373 } 374 375 @Override /* Overridden from HttpServletRequest */ 376 public int getIntHeader(String name) { 377 var s = getHeader(name); 378 return ie(s) ? 0 : Integer.parseInt(s); 379 } 380 381 @Override /* Overridden from HttpServletRequest */ 382 public String getLocalAddr() { return localAddr; } 383 384 @Override /* Overridden from HttpServletRequest */ 385 public Locale getLocale() { return locale; } 386 387 @Override /* Overridden from HttpServletRequest */ 388 public Enumeration<Locale> getLocales() { return Collections.enumeration(l(locale)); } 389 390 @Override /* Overridden from HttpServletRequest */ 391 public String getLocalName() { return localName; } 392 393 @Override /* Overridden from HttpServletRequest */ 394 public int getLocalPort() { return localPort; } 395 396 @Override /* Overridden from HttpServletRequest */ 397 public String getMethod() { return method; } 398 399 @Override /* Overridden from HttpServletRequest */ 400 public String getParameter(String name) { 401 var s = getParameterMap().get(name); 402 return s == null || s.length == 0 ? null : s[0]; 403 } 404 405 @Override /* Overridden from HttpServletRequest */ 406 public Map<String,String[]> getParameterMap() { 407 if (eqic("POST", method)) { 408 if (formDataMap == null) { 409 var listMap = RestUtils.parseQuery(read(content)); 410 formDataMap = map(); 411 for (var e : listMap.entrySet()) { 412 if (e.getValue() == null) 413 formDataMap.put(e.getKey(), null); 414 else 415 formDataMap.put(e.getKey(), array(e.getValue(), String.class)); 416 } 417 } 418 return formDataMap; 419 } 420 return queryDataMap; 421 } 422 423 @Override /* Overridden from HttpServletRequest */ 424 public Enumeration<String> getParameterNames() { return enumeration(toList(getParameterMap().keySet())); } 425 426 @Override /* Overridden from HttpServletRequest */ 427 public String[] getParameterValues(String name) { 428 return getParameterMap().get(name); 429 } 430 431 @Override /* Overridden from HttpServletRequest */ 432 public Part getPart(String name) throws IOException, ServletException { 433 return null; 434 } 435 436 @Override /* Overridden from HttpServletRequest */ 437 public Collection<Part> getParts() throws IOException, ServletException { return Collections.emptyList(); } 438 439 @Override /* Overridden from HttpServletRequest */ 440 public String getPathInfo() { 441 if (pathInfo == null) { 442 pathInfo = getRequestURI(); 443 if (ine(contextPath)) 444 pathInfo = pathInfo.substring(contextPath.length()); 445 if (ine(servletPath)) 446 pathInfo = pathInfo.substring(servletPath.length()); 447 } 448 return nie(urlDecode(pathInfo)); 449 } 450 451 @Override /* Overridden from HttpServletRequest */ 452 public String getPathTranslated() { 453 if (pathTranslated == null) 454 pathTranslated = "/mock-path" + getPathInfo(); 455 return pathTranslated; 456 } 457 458 @Override /* Overridden from HttpServletRequest */ 459 public String getProtocol() { return protocol; } 460 461 @Override 462 public String getProtocolRequestId() { return null; } 463 464 @Override /* Overridden from HttpServletRequest */ 465 public String getQueryString() { 466 if (queryString == null) { 467 if (queryDataMap.isEmpty()) 468 queryString = ""; 469 else { 470 var sb = new StringBuilder(); 471 queryDataMap.forEach((k, v) -> { 472 if (v == null) 473 sb.append(sb.isEmpty() ? "" : "&").append(urlEncode(k)); 474 else 475 for (var v2 : v) 476 sb.append(sb.isEmpty() ? "" : "&").append(urlEncode(k)).append('=').append(urlEncode(v2)); 477 }); 478 queryString = sb.toString(); 479 } 480 } 481 return isEmpty(queryString) ? null : queryString; 482 } 483 484 @Override /* Overridden from HttpServletRequest */ 485 public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream(), characterEncoding)); } 486 487 @Override /* Overridden from HttpServletRequest */ 488 public String getRemoteAddr() { return remoteAddr; } 489 490 @Override /* Overridden from HttpServletRequest */ 491 public String getRemoteHost() { return remoteHost; } 492 493 @Override /* Overridden from HttpServletRequest */ 494 public int getRemotePort() { return remotePort; } 495 496 @Override /* Overridden from HttpServletRequest */ 497 public String getRemoteUser() { return remoteUser; } 498 499 @Override /* Overridden from HttpServletRequest */ 500 public RequestDispatcher getRequestDispatcher(String path) { 501 return requestDispatcher.get(path); 502 } 503 504 @Override /* Overridden from HttpServletRequest */ 505 public String getRequestedSessionId() { return requestedSessionId; } 506 507 @Override 508 public String getRequestId() { return null; } 509 510 @Override /* Overridden from HttpServletRequest */ 511 public String getRequestURI() { 512 if (requestURI == null) { 513 requestURI = uri; 514 requestURI = requestURI.replaceAll("^\\w+\\:\\/\\/[^\\/]+", "").replaceAll("\\?.*$", ""); 515 } 516 return requestURI; 517 } 518 519 @Override /* Overridden from HttpServletRequest */ 520 public StringBuffer getRequestURL() { return new StringBuffer(uri.replaceAll("\\?.*$", "")); } 521 522 @Override /* Overridden from HttpServletRequest */ 523 public String getScheme() { return scheme; } 524 525 @Override /* Overridden from HttpServletRequest */ 526 public String getServerName() { return serverName; } 527 528 @Override /* Overridden from HttpServletRequest */ 529 public int getServerPort() { return serverPort; } 530 531 @Override 532 public ServletConnection getServletConnection() { return null; } 533 534 @Override /* Overridden from HttpServletRequest */ 535 public ServletContext getServletContext() { return servletContext; } 536 537 @Override /* Overridden from HttpServletRequest */ 538 public String getServletPath() { return servletPath; } 539 540 @Override /* Overridden from HttpServletRequest */ 541 public HttpSession getSession() { return httpSession; } 542 543 @Override /* Overridden from HttpServletRequest */ 544 public HttpSession getSession(boolean create) { 545 return httpSession; 546 } 547 548 @Override /* Overridden from HttpServletRequest */ 549 public Principal getUserPrincipal() { return userPrincipal; } 550 551 /** 552 * Fluent setter. 553 * 554 * @param name Header name. 555 * @param value 556 * Header value. 557 * <br>The value is converted to a simple string using {@link Object#toString()}. 558 * @return This object. 559 */ 560 public MockServletRequest header(String name, Object value) { 561 if (nn(value)) { 562 var v1 = (value instanceof String[] stringArray) ? stringArray : a(value.toString()); 563 var v2 = headerMap.get(name); 564 var v3 = combine(v2, v1); 565 headerMap.put(name, v3); 566 } 567 return this; 568 } 569 570 /** 571 * Fluent setter. 572 * 573 * @param value The HTTP session. 574 * @return This object. 575 */ 576 public MockServletRequest httpSession(HttpSession value) { 577 httpSession = value; 578 return this; 579 } 580 581 @Override /* Overridden from HttpServletRequest */ 582 public boolean isAsyncStarted() { return false; } 583 584 @Override /* Overridden from HttpServletRequest */ 585 public boolean isAsyncSupported() { return false; } 586 587 @Override /* Overridden from HttpServletRequest */ 588 public boolean isRequestedSessionIdFromCookie() { return false; } 589 590 @Override /* Overridden from HttpServletRequest */ 591 public boolean isRequestedSessionIdFromURL() { return false; } 592 593 @Override /* Overridden from HttpServletRequest */ 594 public boolean isRequestedSessionIdValid() { return false; } 595 596 @Override /* Overridden from HttpServletRequest */ 597 public boolean isSecure() { return false; } 598 599 @Override /* Overridden from HttpServletRequest */ 600 public boolean isUserInRole(String role) { 601 return roles.contains(role); 602 } 603 604 /** 605 * Fluent setter. 606 * 607 * @param value The local address. 608 * @return This object. 609 */ 610 public MockServletRequest localAddr(String value) { 611 localAddr = value; 612 return this; 613 } 614 615 /** 616 * Fluent setter. 617 * 618 * @param value The locale. 619 * @return This object. 620 */ 621 public MockServletRequest locale(Locale value) { 622 locale = value; 623 return this; 624 } 625 626 /** 627 * Fluent setter. 628 * 629 * @param value The local name. 630 * @return This object. 631 */ 632 public MockServletRequest localName(String value) { 633 localName = value; 634 return this; 635 } 636 637 /** 638 * Fluent setter. 639 * 640 * @param value The local port. 641 * @return This object. 642 */ 643 public MockServletRequest localPort(int value) { 644 localPort = value; 645 return this; 646 } 647 648 @Override /* Overridden from HttpServletRequest */ 649 public void login(String username, String password) throws ServletException { 650 // No-op: Mock implementation - full functionality not required 651 } 652 653 @Override /* Overridden from HttpServletRequest */ 654 public void logout() throws ServletException { 655 // No-op: Mock implementation - full functionality not required 656 } 657 658 /** 659 * Fluent setter. 660 * 661 * @param value The method name for this request. 662 * @return This object. 663 */ 664 public MockServletRequest method(String value) { 665 method = value; 666 return this; 667 } 668 669 /** 670 * Enabled debug mode on this request. 671 * 672 * <p> 673 * Prevents errors from being logged on the server side if no-trace per-request is enabled. 674 * 675 * @param value The enable flag value. 676 * @return This object. 677 */ 678 public MockServletRequest noTrace(boolean value) { 679 if (value) 680 header("No-Trace", "true"); 681 return this; 682 } 683 684 /** 685 * Fluent setter. 686 * 687 * @param value The path info. 688 * @return This object. 689 */ 690 public MockServletRequest pathInfo(String value) { 691 pathInfo = value; 692 return this; 693 } 694 695 /** 696 * Fluent setter. 697 * 698 * @param value The path translated. 699 * @return This object. 700 */ 701 public MockServletRequest pathTranslated(String value) { 702 pathTranslated = value; 703 return this; 704 } 705 706 /** 707 * Adds the specified parent path variables to this servlet request. 708 * 709 * <p> 710 * See {@link org.apache.juneau.rest.mock.classic.MockRestClient.Builder#pathVars(Map)} for an example. 711 * 712 * @param pathVars The parent path variables to add. Can be <jk>null</jk> (no-op). 713 * @return This object. 714 * @see org.apache.juneau.rest.mock.classic.MockRestClient.Builder#pathVars(Map) 715 */ 716 public MockServletRequest pathVars(Map<String,String> pathVars) { 717 if (nn(pathVars)) 718 this.attributeMap.put("juneau.pathVars", new TreeMap<>(pathVars)); 719 return this; 720 } 721 722 /** 723 * Add resolved path variables to this client. 724 * 725 * <p> 726 * Identical to {@link #pathVars(Map)} but allows you to specify as a list of key/value pairs. 727 * 728 * @param pairs The key/value pairs. Must be an even number of parameters. 729 * @return This object. 730 */ 731 public MockServletRequest pathVars(String...pairs) { 732 return pathVars(mb(String.class, String.class).addPairs((Object[])pairs).build()); 733 } 734 735 /** 736 * Fluent setter. 737 * 738 * @param value The protocol. 739 * @return This object. 740 */ 741 public MockServletRequest protocol(String value) { 742 protocol = value; 743 return this; 744 } 745 746 /** 747 * Fluent setter. 748 * 749 * @param value The query string. 750 * @return This object. 751 */ 752 public MockServletRequest queryString(String value) { 753 queryString = value; 754 return this; 755 } 756 757 /** 758 * Fluent setter. 759 * 760 * @param value The remote address. 761 * @return This object. 762 */ 763 public MockServletRequest remoteAddr(String value) { 764 remoteAddr = value; 765 return this; 766 } 767 768 /** 769 * Fluent setter. 770 * 771 * @param value The remote port. 772 * @return This object. 773 */ 774 public MockServletRequest remoteHost(String value) { 775 remoteHost = value; 776 return this; 777 } 778 779 /** 780 * Fluent setter. 781 * 782 * @param value The remote port. 783 * @return This object. 784 */ 785 public MockServletRequest remotePort(int value) { 786 remotePort = value; 787 return this; 788 } 789 790 /** 791 * Fluent setter. 792 * 793 * @param value The remote user. 794 * @return This object. 795 */ 796 public MockServletRequest remoteUser(String value) { 797 remoteUser = value; 798 return this; 799 } 800 801 @Override /* Overridden from HttpServletRequest */ 802 public void removeAttribute(String name) { 803 this.attributeMap.remove(name); 804 } 805 806 /** 807 * Fluent setter. 808 * 809 * @param name The path to resolve. 810 * @param value The request dispatcher. 811 * @return This object. 812 */ 813 public MockServletRequest requestDispatcher(String name, RequestDispatcher value) { 814 this.requestDispatcher.put(name, value); 815 return this; 816 } 817 818 /** 819 * Fluent setter. 820 * 821 * @param value The requested session ID. 822 * @return This object. 823 */ 824 public MockServletRequest requestedSessionId(String value) { 825 requestedSessionId = value; 826 return this; 827 } 828 829 /** 830 * Fluent setter. 831 * 832 * @param value The request URI. 833 * @return This object. 834 */ 835 public MockServletRequest requestURI(String value) { 836 requestURI = value; 837 return this; 838 } 839 840 /** 841 * Sets the specified role on this request. 842 * 843 * @param role The role to add to this request (e.g. <js>"ROLE_ADMIN"</js>). 844 * @return This object. 845 */ 846 public MockServletRequest role(String role) { 847 this.roles = set(role); 848 return this; 849 } 850 851 /** 852 * Sets the specified roles on this request. 853 * 854 * @param roles The roles to add to this request (e.g. <js>"ROLE_ADMIN"</js>). 855 * @return This object. 856 */ 857 public MockServletRequest roles(String...roles) { 858 this.roles = set(roles); 859 return this; 860 } 861 862 /** 863 * Fluent setter. 864 * 865 * @param value The scheme. 866 * @return This object. 867 */ 868 public MockServletRequest scheme(String value) { 869 scheme = value; 870 return this; 871 } 872 873 /** 874 * Fluent setter. 875 * 876 * @param value The server name. 877 * @return This object. 878 */ 879 public MockServletRequest serverName(String value) { 880 serverName = value; 881 return this; 882 } 883 884 /** 885 * Fluent setter. 886 * 887 * @param value The server port. 888 * @return This object. 889 */ 890 public MockServletRequest serverPort(int value) { 891 serverPort = value; 892 return this; 893 } 894 895 /** 896 * Fluent setter. 897 * 898 * @param value The servlet context. 899 * @return This object. 900 */ 901 public MockServletRequest servletContext(ServletContext value) { 902 servletContext = value; 903 return this; 904 } 905 906 /** 907 * Fluent setter. 908 * 909 * @param value The servlet path. 910 * @return This object. 911 */ 912 public MockServletRequest servletPath(String value) { 913 servletPath = value; 914 return this; 915 } 916 917 @Override /* Overridden from HttpServletRequest */ 918 public void setAttribute(String name, Object o) { 919 this.attributeMap.put(name, o); 920 } 921 922 @Override /* Overridden from HttpServletRequest */ 923 public void setCharacterEncoding(String characterEncoding) throws UnsupportedEncodingException { this.characterEncoding = characterEncoding; } 924 925 @Override /* Overridden from HttpServletRequest */ 926 public AsyncContext startAsync() throws IllegalStateException { 927 return null; 928 } 929 930 @Override /* Overridden from HttpServletRequest */ 931 public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException { 932 return null; 933 } 934 935 @Override /* Overridden from HttpServletRequest */ 936 public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException { 937 return null; 938 } 939 940 /** 941 * Fluent setter. 942 * 943 * @param uri The URI of the request. 944 * @return This object. 945 */ 946 public MockServletRequest uri(String uri) { 947 uri = emptyIfNull(uri); 948 this.uri = uri; 949 950 if (uri.indexOf('?') != -1) { 951 var qs = uri.substring(uri.indexOf('?') + 1); 952 if (qs.indexOf('#') != -1) 953 qs = qs.substring(0, qs.indexOf('#')); 954 queryString = qs; 955 var listMap = RestUtils.parseQuery(qs); 956 for (var e : listMap.entrySet()) { 957 if (e.getValue() == null) 958 queryDataMap.put(e.getKey(), null); 959 else 960 queryDataMap.put(e.getKey(), array(e.getValue(), String.class)); 961 } 962 } 963 964 return this; 965 } 966 967 /** 968 * Fluent setter. 969 * 970 * @param value The user principal. 971 * @return This object. 972 */ 973 public MockServletRequest userPrincipal(Principal value) { 974 userPrincipal = value; 975 return this; 976 } 977 978 /** 979 * Sets the JUL log level to transiently apply to the target resource's logger for the duration of this 980 * request's dispatch. 981 * 982 * <p> 983 * This is a pure data holder read by the mock transport at the actual dispatch call site, which is responsible 984 * for saving the resource logger's current level, applying this value, invoking {@code RestContext.execute(...)}, 985 * and restoring the prior level in a {@code finally} block. The mutation is therefore transient and never leaks 986 * across requests or tests. Replaces the removed {@code debug(boolean)} flag, which set a now-meaningless 987 * {@code Debug} request header. 988 * 989 * @param value The log level to apply during dispatch, or <jk>null</jk> for no override. 990 * @return This object. 991 */ 992 public MockServletRequest logLevel(Level value) { 993 logLevel = value; 994 return this; 995 } 996 997 /** 998 * Returns the log level set via {@link #logLevel(Level)}. 999 * 1000 * @return The log level to apply during dispatch, or <jk>null</jk> if not set. 1001 */ 1002 public Level getLogLevel() { 1003 return logLevel; 1004 } 1005}