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; 014 015import static java.util.Collections.*; 016import static java.util.logging.Level.*; 017import static javax.servlet.http.HttpServletResponse.*; 018import static org.apache.juneau.html.HtmlDocSerializer.*; 019import static org.apache.juneau.internal.IOUtils.*; 020import static org.apache.juneau.serializer.Serializer.*; 021 022import java.io.*; 023import java.lang.reflect.Method; 024import java.net.*; 025import java.nio.charset.*; 026import java.text.*; 027import java.util.*; 028import java.util.logging.*; 029 030import javax.servlet.*; 031import javax.servlet.http.*; 032 033import org.apache.juneau.*; 034import org.apache.juneau.config.*; 035import org.apache.juneau.dto.swagger.*; 036import org.apache.juneau.http.*; 037import org.apache.juneau.internal.*; 038import org.apache.juneau.parser.*; 039import org.apache.juneau.rest.annotation.*; 040import org.apache.juneau.rest.widget.*; 041import org.apache.juneau.serializer.*; 042import org.apache.juneau.svl.*; 043import org.apache.juneau.uon.*; 044import org.apache.juneau.utils.*; 045 046/** 047 * Represents an HTTP request for a REST resource. 048 * 049 * <p> 050 * Equivalent to {@link HttpServletRequest} except with some additional convenience methods. 051 * 052 * <p> 053 * For reference, given the URL <js>"http://localhost:9080/contextRoot/servletPath/foo?bar=baz#qux"</js>, the 054 * following methods return the following values.... 055 * <table class='styled'> 056 * <tr><th>Method</th><th>Value</th></tr> 057 * <tr><td>{@code getContextPath()}</td><td>{@code /contextRoot}</td></tr> 058 * <tr><td>{@code getPathInfo()}</td><td>{@code /foo}</td></tr> 059 * <tr><td>{@code getPathTranslated()}</td><td>{@code path-to-deployed-war-on-filesystem/foo}</td></tr> 060 * <tr><td>{@code getQueryString()}</td><td>{@code bar=baz}</td></tr> 061 * <tr><td>{@code getRequestURI()}</td><td>{@code /contextRoot/servletPath/foo}</td></tr> 062 * <tr><td>{@code getRequestURL()}</td><td>{@code http://localhost:9080/contextRoot/servletPath/foo}</td></tr> 063 * <tr><td>{@code getServletPath()}</td><td>{@code /servletPath}</td></tr> 064 * </table> 065 * 066 * <h5 class='section'>See Also:</h5> 067 * <ul> 068 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RestRequest">Overview > juneau-rest-server > RestRequest</a> 069 * </ul> 070 */ 071@SuppressWarnings({ "unchecked", "unused" }) 072public final class RestRequest extends HttpServletRequestWrapper { 073 074 private final RestContext context; 075 private RestJavaMethod restJavaMethod; 076 077 private final String method; 078 private RequestBody body; 079 private Method javaMethod; 080 private RequestProperties properties; 081 private final boolean debug; 082 private BeanSession beanSession; 083 private VarResolverSession varSession; 084 private final RequestQuery queryParams; 085 private RequestFormData formData; 086 private RequestPathMatch pathParams; 087 private boolean isPost; 088 private UriContext uriContext; 089 private String charset; 090 private RequestHeaders headers; 091 private Config cf; 092 private Swagger swagger; 093 094 /** 095 * Constructor. 096 */ 097 RestRequest(RestContext context, HttpServletRequest req) throws ServletException { 098 super(req); 099 this.context = context; 100 101 try { 102 isPost = req.getMethod().equalsIgnoreCase("POST"); 103 104 // If this is a POST, we want to parse the query parameters ourselves to prevent 105 // the servlet code from processing the HTTP body as URL-Encoded parameters. 106 queryParams = new RequestQuery(); 107 if (isPost) 108 RestUtils.parseQuery(getQueryString(), queryParams); 109 else 110 queryParams.putAll(req.getParameterMap()); 111 112 113 // Get the HTTP method. 114 // Can be overridden through a "method" GET attribute. 115 String _method = super.getMethod(); 116 117 String m = getQuery().getString("method"); 118 if (context.allowMethodParam(m)) 119 _method = m; 120 121 method = _method; 122 123 headers = new RequestHeaders(); 124 for (Enumeration<String> e = getHeaderNames(); e.hasMoreElements();) { 125 String name = e.nextElement(); 126 headers.put(name, super.getHeaders(name)); 127 } 128 129 body = new RequestBody(this); 130 131 if (context.isAllowBodyParam()) { 132 String b = getQuery().getString("body"); 133 if (b != null) { 134 headers.put("Content-Type", UonSerializer.DEFAULT.getResponseContentType()); 135 body.load(b.getBytes(UTF8)); 136 } 137 } 138 139 if (context.isAllowHeaderParams()) 140 headers.setQueryParams(queryParams); 141 142 debug = "true".equals(getQuery().getString("debug", "false")) || "true".equals(getHeaders().getString("Debug", "false")); 143 144 this.pathParams = new RequestPathMatch(); 145 146 } catch (RestException e) { 147 throw e; 148 } catch (Exception e) { 149 throw new ServletException(e); 150 } 151 } 152 153 /* 154 * Called from RestServlet after a match has been made but before the guard or method invocation. 155 */ 156 final void init(RestJavaMethod rjm, RequestProperties properties) { 157 this.restJavaMethod = rjm; 158 this.javaMethod = rjm.method; 159 this.properties = properties; 160 this.beanSession = rjm.beanContext.createSession(); 161 this.pathParams 162 .parser(rjm.partParser) 163 .beanSession(beanSession); 164 this.queryParams 165 .addDefault(rjm.defaultQuery) 166 .parser(rjm.partParser) 167 .beanSession(beanSession); 168 this.headers 169 .addDefault(rjm.defaultRequestHeaders) 170 .addDefault(context.getDefaultRequestHeaders()) 171 .parser(rjm.partParser) 172 .beanSession(beanSession); 173 this.body 174 .encoders(rjm.encoders) 175 .parsers(rjm.parsers) 176 .headers(headers) 177 .beanSession(beanSession) 178 .maxInput(rjm.maxInput); 179 180 String stylesheet = getQuery().getString("stylesheet"); 181 if (stylesheet != null) 182 getSession().setAttribute("stylesheet", stylesheet.replace(' ', '$')); // Prevent SVL insertion. 183 stylesheet = (String)getSession().getAttribute("stylesheet"); 184 if (stylesheet != null) 185 properties.put(HTMLDOC_stylesheet, new String[]{stylesheet}); 186 187 if (debug) { 188 String msg = "" 189 + "\n=== HTTP Request (incoming) ====================================================" 190 + toString() 191 + "\n=== END ========================================================================"; 192 context.getLogger().log(Level.WARNING, msg); 193 } 194 195 if (isPlainText()) 196 this.properties.put(SERIALIZER_useWhitespace, true); 197 } 198 199 /** 200 * Returns a string of the form <js>"HTTP method-name full-url"</js> 201 * 202 * @return A description string of the request. 203 */ 204 public String getDescription() { 205 String qs = getQueryString(); 206 return "HTTP " + getMethod() + " " + getRequestURI() + (qs == null ? "" : "?" + qs); 207 } 208 209 /** 210 * Same as {@link #getAttribute(String)} but returns a default value if not found. 211 * 212 * @param name The request attribute name. 213 * @param def The default value if the attribute doesn't exist. 214 * @return The request attribute value. 215 */ 216 public Object getAttribute(String name, Object def) { 217 Object o = super.getAttribute(name); 218 return (o == null ? def : o); 219 } 220 221 /** 222 * Shorthand method for calling {@link #setAttribute(String, Object)} fluently. 223 * 224 * @param name The request attribute name. 225 * @param value The request attribute value. 226 * @return This object (for method chaining). 227 */ 228 public RestRequest attr(String name, Object value) { 229 setAttribute(name, value); 230 return this; 231 } 232 233 234 //-------------------------------------------------------------------------------- 235 // Properties 236 //-------------------------------------------------------------------------------- 237 238 /** 239 * Retrieve the properties active for this request. 240 * 241 * <p> 242 * This contains all resource and method level properties from the following: 243 * <ul> 244 * <li class='ja'>{@link RestResource#properties()} 245 * <li class='ja'>{@link RestMethod#properties()} 246 * <li class='jm'>{@link RestContextBuilder#set(String, Object)} 247 * </ul> 248 * 249 * <p> 250 * The returned object is modifiable and allows you to override session-level properties before 251 * they get passed to the serializers. 252 * <br>However, properties are open-ended, and can be used for any purpose. 253 * 254 * <h5 class='section'>Example:</h5> 255 * <p class='bcode'> 256 * <ja>@RestMethod</ja>( 257 * properties={ 258 * <ja>@Property</ja>(name=<jsf>SERIALIZER_sortMaps</jsf>, value=<js>"false"</js>) 259 * } 260 * ) 261 * <jk>public</jk> Map doGet(RestRequest req, <ja>@Query</ja>(<js>"sortMaps"</js>) Boolean sortMaps) { 262 * 263 * <jc>// Override value if specified through query parameter.</jc> 264 * <jk>if</jk> (sortMaps != <jk>null</jk>) 265 * req.getProperties().put(<jsf>SERIALIZER_sortMaps</jsf>, sortMaps); 266 * 267 * <jk>return</jk> <jsm>getMyMap</jsm>(); 268 * } 269 * </p> 270 * 271 * <h5 class='section'>See Also:</h5> 272 * <ul> 273 * <li class='jm'>{@link #prop(String, Object)} 274 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Properties">Overview > juneau-rest-server > Properties</a> 275 * </ul> 276 * 277 * @return The properties active for this request. 278 */ 279 public RequestProperties getProperties() { 280 return this.properties; 281 } 282 283 /** 284 * Shortcut for calling <code>getProperties().append(name, value);</code> fluently. 285 * 286 * @param name The property name. 287 * @param value The property value. 288 * @return This object (for method chaining). 289 */ 290 public RestRequest prop(String name, Object value) { 291 this.properties.append(name, value); 292 return this; 293 } 294 295 296 //-------------------------------------------------------------------------------- 297 // Headers 298 //-------------------------------------------------------------------------------- 299 300 /** 301 * Request headers. 302 * 303 * <p> 304 * Returns a {@link RequestHeaders} object that encapsulates access to HTTP headers on the request. 305 * 306 * <h5 class='section'>Example:</h5> 307 * <p class='bcode'> 308 * <ja>@RestMethod</ja>(...) 309 * <jk>public</jk> Object myMethod(RestRequest req) { 310 * 311 * <jc>// Get access to headers.</jc> 312 * RequestHeaders h = req.getHeaders(); 313 * 314 * <jc>// Add a default value.</jc> 315 * h.addDefault(<js>"ETag"</js>, <jsf>DEFAULT_UUID</jsf>); 316 * 317 * <jc>// Get a header value as a POJO.</jc> 318 * UUID etag = h.get(<js>"ETag"</js>, UUID.<jk>class</jk>); 319 * 320 * <jc>// Get a standard header.</jc> 321 * CacheControl = h.getCacheControl(); 322 * } 323 * </p> 324 * 325 * <h5 class='section'>Notes:</h5> 326 * <ul class='spaced-list'> 327 * <li> 328 * This object is modifiable. 329 * <li> 330 * Values are converted from strings using the registered {@link RestContext#REST_partParser part-parser} on the resource class. 331 * <li> 332 * The {@link RequestHeaders} object can also be passed as a parameter on the method. 333 * <li> 334 * The {@link Header @Header} annotation can be used to access individual header values. 335 * </ul> 336 * 337 * <h5 class='section'>See Also:</h5> 338 * <ul> 339 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestHeaders">Overview > juneau-rest-server > RequestHeaders</a> 340 * </ul> 341 * 342 * @return 343 * The headers on this request. 344 * <br>Never <jk>null</jk>. 345 */ 346 public RequestHeaders getHeaders() { 347 return headers; 348 } 349 350 @Override /* ServletRequest */ 351 public String getHeader(String name) { 352 return getHeaders().getString(name); 353 } 354 355 @Override /* ServletRequest */ 356 public Enumeration<String> getHeaders(String name) { 357 String[] v = headers.get(name); 358 if (v == null || v.length == 0) 359 return Collections.enumeration(Collections.EMPTY_LIST); 360 return Collections.enumeration(Arrays.asList(v)); 361 } 362 363 /** 364 * Returns the media types that are valid for <code>Accept</code> headers on the request. 365 * 366 * @return The set of media types registered in the serializer group of this request. 367 */ 368 public List<MediaType> getProduces() { 369 return restJavaMethod.supportedAcceptTypes; 370 } 371 372 /** 373 * Returns the media types that are valid for <code>Content-Type</code> headers on the request. 374 * 375 * @return The set of media types registered in the parser group of this request. 376 */ 377 public List<MediaType> getConsumes() { 378 return restJavaMethod.supportedContentTypes; 379 } 380 381 /** 382 * Sets the charset to expect on the request body. 383 */ 384 @Override /* ServletRequest */ 385 public void setCharacterEncoding(String charset) { 386 this.charset = charset; 387 } 388 389 /** 390 * Returns the charset specified on the <code>Content-Type</code> header, or <js>"UTF-8"</js> if not specified. 391 */ 392 @Override /* ServletRequest */ 393 public String getCharacterEncoding() { 394 if (charset == null) { 395 // Determine charset 396 // NOTE: Don't use super.getCharacterEncoding() because the spec is implemented inconsistently. 397 // Jetty returns the default charset instead of null if the character is not specified on the request. 398 String h = getHeader("Content-Type"); 399 if (h != null) { 400 int i = h.indexOf(";charset="); 401 if (i > 0) 402 charset = h.substring(i+9).trim(); 403 } 404 if (charset == null) 405 charset = restJavaMethod.defaultCharset; 406 if (! Charset.isSupported(charset)) 407 throw new RestException(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported charset in header ''Content-Type'': ''{0}''", h); 408 } 409 return charset; 410 } 411 412 @Override /* ServletRequest */ 413 public Locale getLocale() { 414 String h = headers.getString("Accept-Language"); 415 if (h != null) { 416 MediaTypeRange[] mr = MediaTypeRange.parse(h); 417 if (mr.length > 0) 418 return toLocale(mr[0].getMediaType().getType()); 419 } 420 return super.getLocale(); 421 } 422 423 @Override /* ServletRequest */ 424 public Enumeration<Locale> getLocales() { 425 String h = headers.getString("Accept-Language"); 426 if (h != null) { 427 MediaTypeRange[] mr = MediaTypeRange.parse(h); 428 if (mr.length > 0) { 429 List<Locale> l = new ArrayList<Locale>(mr.length); 430 for (MediaTypeRange r : mr) 431 l.add(toLocale(r.getMediaType().getType())); 432 return enumeration(l); 433 } 434 } 435 return super.getLocales(); 436 } 437 438 439 //-------------------------------------------------------------------------------- 440 // Query parameters 441 //-------------------------------------------------------------------------------- 442 443 /** 444 * Query parameters. 445 * 446 * <p> 447 * Returns a {@link RequestQuery} object that encapsulates access to URL GET parameters. 448 * 449 * <p> 450 * Similar to {@link #getParameterMap()} but only looks for query parameters in the URL and not form posts. 451 * 452 * <h5 class='section'>Example:</h5> 453 * <p class='bcode'> 454 * <ja>@RestMethod</ja>(...) 455 * <jk>public void</jk> doGet(RestRequest req) { 456 * 457 * <jc>// Get access to query parameters on the URL.</jc> 458 * RequestQuery q = req.getQuery(); 459 * 460 * <jc>// Get query parameters converted to various types.</jc> 461 * <jk>int</jk> p1 = q.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>); 462 * String p2 = q.get(<js>"p2"</js>, String.<jk>class</jk>); 463 * UUID p3 = q.get(<js>"p3"</js>, UUID.<jk>class</jk>); 464 * } 465 * </p> 466 * 467 * <h5 class='section'>Notes:</h5> 468 * <ul class='spaced-list'> 469 * <li> 470 * This object is modifiable. 471 * <li> 472 * This method can be used to retrieve query parameters without triggering the underlying servlet API to load and parse the request body. 473 * <li> 474 * Values are converted from strings using the registered {@link RestContext#REST_partParser part-parser} on the resource class. 475 * <li> 476 * The {@link RequestQuery} object can also be passed as a parameter on the method. 477 * <li> 478 * The {@link Query @Query} annotation can be used to access individual query parameter values. 479 * </ul> 480 * 481 * <h5 class='section'>See Also:</h5> 482 * <ul> 483 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestQuery">Overview > juneau-rest-server > RequestQuery</a> 484 * </ul> 485 * 486 * @return 487 * The query parameters as a modifiable map. 488 * <br>Never <jk>null</jk>. 489 */ 490 public RequestQuery getQuery() { 491 return queryParams; 492 } 493 494 /** 495 * Shortcut for calling <code>getQuery().getString(name)</code>. 496 * 497 * @param name The query parameter name. 498 * @return The query parameter value, or <jk>null</jk> if not found. 499 */ 500 public String getQuery(String name) { 501 return getQuery().getString(name); 502 } 503 504 505 //-------------------------------------------------------------------------------- 506 // Form data parameters 507 //-------------------------------------------------------------------------------- 508 509 /** 510 * Form-data. 511 * 512 * <p> 513 * Returns a {@link RequestFormData} object that encapsulates access to form post parameters. 514 * 515 * <p> 516 * Similar to {@link #getParameterMap()}, but only looks for form data in the HTTP body. 517 * 518 * <h5 class='section'>Example:</h5> 519 * <p class='bcode'> 520 * <ja>@RestMethod</ja>(...) 521 * <jk>public void</jk> doPost(RestRequest req) { 522 * 523 * <jc>// Get access to parsed form data parameters.</jc> 524 * RequestFormData fd = req.getFormData(); 525 * 526 * <jc>// Get form data parameters converted to various types.</jc> 527 * <jk>int</jk> p1 = fd.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>); 528 * String p2 = fd.get(<js>"p2"</js>, String.<jk>class</jk>); 529 * UUID p3 = fd.get(<js>"p3"</js>, UUID.<jk>class</jk>); 530 * } 531 * </p> 532 * 533 * <h5 class='section'>Notes:</h5> 534 * <ul class='spaced-list'> 535 * <li> 536 * This object is modifiable. 537 * <li> 538 * Values are converted from strings using the registered {@link RestContext#REST_partParser part-parser} on the resource class. 539 * <li> 540 * The {@link RequestFormData} object can also be passed as a parameter on the method. 541 * <li> 542 * The {@link FormData @FormDAta} annotation can be used to access individual form data parameter values. 543 * </ul> 544 * 545 * <h5 class='section'>See Also:</h5> 546 * <ul> 547 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestFormData">Overview > juneau-rest-server > RequestFormData</a> 548 * </ul> 549 * 550 * @return 551 * The URL-encoded form data from the request. 552 * <br>Never <jk>null</jk>. 553 * @see org.apache.juneau.rest.annotation.FormData 554 */ 555 public RequestFormData getFormData() { 556 try { 557 if (formData == null) { 558 formData = new RequestFormData(); 559 formData.setParser(restJavaMethod.partParser).setBeanSession(beanSession); 560 if (! body.isLoaded()) { 561 formData.putAll(getParameterMap()); 562 } else { 563 Map<String,String[]> m = RestUtils.parseQuery(body.getReader()); 564 for (Map.Entry<String,String[]> e : m.entrySet()) { 565 for (String v : e.getValue()) 566 formData.put(e.getKey(), v); 567 } 568 } 569 } 570 formData.addDefault(restJavaMethod.defaultFormData); 571 return formData; 572 } catch (Exception e) { 573 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 574 } 575 } 576 577 /** 578 * Shortcut for calling <code>getFormData().getString(name)</code>. 579 * 580 * @param name The form data parameter name. 581 * @return The form data parameter value, or <jk>null<jk> if not found. 582 */ 583 public String getFormData(String name) { 584 return getFormData().getString(name); 585 } 586 587 588 //-------------------------------------------------------------------------------- 589 // Path parameters 590 //-------------------------------------------------------------------------------- 591 592 /** 593 * Request path match. 594 * 595 * <p> 596 * Returns a {@link RequestPathMatch} object that encapsulates access to everything related to the URL path. 597 * 598 * <h5 class='section'>Example:</h5> 599 * <p class='bcode'> 600 * <ja>@RestMethod</ja>(..., path=<js>"/{foo}/{bar}/{baz}/*"</js>) 601 * <jk>public void</jk> doGet(RestRequest req) { 602 * 603 * <jc>// Get access to path data.</jc> 604 * RequestPathMatch pm = req.getPathMatch(); 605 * 606 * <jc>// Example URL: /123/qux/true/quux</jc> 607 * 608 * <jk>int</jk> foo = pm.getInt(<js>"foo"</js>); <jc>// =123</jc> 609 * String bar = pm.getString(<js>"bar"</js>); <jc>// =qux</jc> 610 * <jk>boolean</jk> baz = pm.getBoolean(<js>"baz"</js>); <jc>// =true</jc> 611 * String remainder = pm.getRemainder(); <jc>// =quux</jc> 612 * } 613 * </p> 614 * 615 * <h5 class='section'>Notes:</h5> 616 * <ul class='spaced-list'> 617 * <li> 618 * This object is modifiable. 619 * <li> 620 * Values are converted from strings using the registered {@link RestContext#REST_partParser part-parser} on the resource class. 621 * <li> 622 * The {@link RequestPathMatch} object can also be passed as a parameter on the method. 623 * <li> 624 * The {@link Path @Path} and {@link PathRemainder @PathRemainder} annotations can be used to access individual values. 625 * </ul> 626 * 627 * <h5 class='section'>See Also:</h5> 628 * <ul> 629 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestPathMatch">Overview > juneau-rest-server > RequestPathMatch</a> 630 * </ul> 631 * 632 * @return 633 * The path data from the URL. 634 * <br>Never <jk>null</jk>. 635 */ 636 public RequestPathMatch getPathMatch() { 637 return pathParams; 638 } 639 640 /** 641 * Shortcut for calling <code>getPathMatch().get(name)</code>. 642 * 643 * @param name The path variable name. 644 * @return The path variable value, or <jk>null</jk> if not found. 645 */ 646 public String getPath(String name) { 647 return getPathMatch().get(name); 648 } 649 650 //-------------------------------------------------------------------------------- 651 // Body methods 652 //-------------------------------------------------------------------------------- 653 654 /** 655 * Request body. 656 * 657 * <p> 658 * Returns a {@link RequestBody} object that encapsulates access to the HTTP request body. 659 * 660 * <h5 class='section'>Example:</h5> 661 * <p class='bcode'> 662 * <ja>@RestMethod</ja>(...) 663 * <jk>public void</jk> doPost2(RestRequest req) { 664 * 665 * <jc>// Convert body to a linked list of Person objects.</jc> 666 * List<Person> l = req.getBody().asType(LinkedList.<jk>class</jk>, Person.<jk>class</jk>); 667 * .. 668 * } 669 * </p> 670 * 671 * <h5 class='section'>Notes:</h5> 672 * <ul class='spaced-list'> 673 * <li> 674 * The {@link RequestBody} object can also be passed as a parameter on the method. 675 * <li> 676 * The {@link Body @Body} annotation can be used to access the body as well. 677 * </ul> 678 * 679 * <h5 class='section'>See Also:</h5> 680 * <ul> 681 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestBody">Overview > juneau-rest-server > RequestBody</a> 682 * </ul> 683 * 684 * @return 685 * The body of this HTTP request. 686 * <br>Never <jk>null</jk>. 687 */ 688 public RequestBody getBody() { 689 return body; 690 } 691 692 /** 693 * Returns the HTTP body content as a {@link Reader}. 694 * 695 * <p> 696 * If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query 697 * string. 698 * 699 * <p> 700 * Automatically handles GZipped input streams. 701 */ 702 @Override /* ServletRequest */ 703 public BufferedReader getReader() throws IOException { 704 return getBody().getReader(); 705 } 706 707 /** 708 * Returns the HTTP body content as an {@link InputStream}. 709 * 710 * <p> 711 * Automatically handles GZipped input streams. 712 * 713 * @return The negotiated input stream. 714 * @throws IOException If any error occurred while trying to get the input stream or wrap it in the GZIP wrapper. 715 */ 716 @Override /* ServletRequest */ 717 public ServletInputStream getInputStream() throws IOException { 718 return getBody().getInputStream(); 719 } 720 721 ServletInputStream getRawInputStream() throws IOException { 722 return super.getInputStream(); 723 } 724 725 726 //-------------------------------------------------------------------------------- 727 // URI-related methods 728 //-------------------------------------------------------------------------------- 729 730 @Override /* HttpServletRequest */ 731 public String getContextPath() { 732 String cp = context.getContextPath(); 733 return cp == null ? super.getContextPath() : cp; 734 } 735 736 @Override /* HttpServletRequest */ 737 public String getServletPath() { 738 String cp = context.getContextPath(); 739 String sp = super.getServletPath(); 740 return cp == null || ! sp.startsWith(cp) ? sp : sp.substring(cp.length()); 741 } 742 743 /** 744 * Returns the URI context of the request. 745 * 746 * <p> 747 * The URI context contains all the information about the URI of the request, such as the servlet URI, context 748 * path, etc... 749 * 750 * @return The URI context of the request. 751 */ 752 public UriContext getUriContext() { 753 if (uriContext == null) { 754 String scheme = getScheme(); 755 int port = getServerPort(); 756 StringBuilder authority = new StringBuilder(getScheme()).append("://").append(getServerName()); 757 if (! (port == 80 && "http".equals(scheme) || port == 443 && "https".equals(scheme))) 758 authority.append(':').append(port); 759 uriContext = new UriContext(authority.toString(), getContextPath(), getServletPath(), StringUtils.urlEncodePath(super.getPathInfo())); 760 } 761 return uriContext; 762 } 763 764 /** 765 * Returns a URI resolver that can be used to convert URIs to absolute or root-relative form. 766 * 767 * @param resolution The URI resolution rule. 768 * @param relativity The relative URI relativity rule. 769 * @return The URI resolver for this request. 770 */ 771 public UriResolver getUriResolver(UriResolution resolution, UriRelativity relativity) { 772 return new UriResolver(resolution, relativity, getUriContext()); 773 } 774 775 /** 776 * Shortcut for calling {@link #getUriResolver()} using {@link UriResolution#ROOT_RELATIVE} and 777 * {@link UriRelativity#RESOURCE} 778 * 779 * @return The URI resolver for this request. 780 */ 781 public UriResolver getUriResolver() { 782 return new UriResolver(UriResolution.ROOT_RELATIVE, UriRelativity.RESOURCE, getUriContext()); 783 } 784 785 /** 786 * Returns the URI for this request. 787 * 788 * <p> 789 * Similar to {@link #getRequestURI()} but returns the value as a {@link URI}. 790 * It also gives you the capability to override the query parameters (e.g. add new query parameters to the existing 791 * URI). 792 * 793 * @param includeQuery If <jk>true</jk> include the query parameters on the request. 794 * @param addQueryParams Augment the request URI with the specified query parameters. 795 * @return A new URI. 796 */ 797 public URI getUri(boolean includeQuery, Map<String,?> addQueryParams) { 798 String uri = getRequestURI(); 799 if (includeQuery || addQueryParams != null) { 800 StringBuilder sb = new StringBuilder(uri); 801 RequestQuery rq = this.queryParams.copy(); 802 if (addQueryParams != null) 803 for (Map.Entry<String,?> e : addQueryParams.entrySet()) 804 rq.put(e.getKey(), e.getValue()); 805 if (! rq.isEmpty()) 806 sb.append('?').append(rq.toQueryString()); 807 uri = sb.toString(); 808 } 809 try { 810 return new URI(uri); 811 } catch (URISyntaxException e) { 812 // Shouldn't happen. 813 throw new RuntimeException(e); 814 } 815 } 816 817 //-------------------------------------------------------------------------------- 818 // Labels 819 //-------------------------------------------------------------------------------- 820 821 /** 822 * Resource information provider. 823 * 824 * <p> 825 * Returns a {@link RestInfoProvider} object that encapsulates all the textual meta-data on this resource such as 826 * descriptions, titles, and Swagger documentation. 827 * 828 * <h5 class='section'>Example:</h5> 829 * <p class='bcode'> 830 * <ja>@RestMethod</ja>(...) 831 * <jk>public void</jk> doGet(RestRequest req) { 832 * 833 * <jc>// Get information provider.</jc> 834 * RestInfoProvider p = req.getInfoProvider(); 835 * 836 * <jc>// Get localized strings.</jc> 837 * String resourceTitle = p.getTitle(req); 838 * String methodDescription = p.getMethodDescription(req.getMethod(), req); 839 * Contact contact = p.getContact(req); 840 * .. 841 * } 842 * </p> 843 * 844 * <h5 class='section'>Notes:</h5> 845 * <ul class='spaced-list'> 846 * <li> 847 * The {@link RestInfoProvider} object can also be passed as a parameter on the method. 848 * </ul> 849 * 850 * <h5 class='section'>See Also:</h5> 851 * <ul> 852 * <li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_infoProvider} 853 * <li class='jic'>{@link org.apache.juneau.rest.RestInfoProvider} 854 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getSiteName()} 855 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getResourceTitle()} 856 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getResourceDescription()} 857 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethodSummary()} 858 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethodDescription()} 859 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.OptionsPages">Overview > juneau-rest-server > OPTIONS Pages</a> 860 * </ul> 861 * 862 * @return 863 * The info provider on the resource. 864 * <br>Never <jk>null</jk>. 865 */ 866 public RestInfoProvider getInfoProvider() { 867 return context.getInfoProvider(); 868 } 869 870 /** 871 * Returns the localized swagger associated with the resource. 872 * 873 * <p> 874 * A shortcut for calling <code>getInfoProvider().getSwagger(request);</code> 875 * 876 * <h5 class='section'>Example:</h5> 877 * <p class='bcode'> 878 * <ja>@RestMethod</ja>(...) 879 * <jk>public</jk> List<Tag> getSwaggerTags(RestRequest req) { 880 * <jk>return</jk> req.getSwagger().getTags(); 881 * } 882 * </p> 883 * 884 * <h5 class='section'>Notes:</h5> 885 * <ul class='spaced-list'> 886 * <li> 887 * The {@link Swagger} object can also be passed as a parameter on the method. 888 * </ul> 889 * 890 * <h5 class='section'>See Also:</h5> 891 * <ul> 892 * <li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_infoProvider} 893 * <li class='jic'>{@link org.apache.juneau.rest.RestInfoProvider} 894 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getInfoProvider()} 895 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.OptionsPages">Overview > juneau-rest-server > OPTIONS Pages</a> 896 * </ul> 897 * 898 * @return 899 * The swagger associated with the resource. 900 * <br>Never <jk>null</jk>. 901 */ 902 public Swagger getSwagger() { 903 try { 904 if (swagger == null) 905 swagger = context.getInfoProvider().getSwagger(this); 906 return swagger; 907 } catch (RestException e) { 908 throw e; 909 } catch (Exception e) { 910 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 911 } 912 } 913 914 /** 915 * Returns the localized site name. 916 * 917 * <p> 918 * The site name is intended to be a title that can be applied to the entire site. 919 * 920 * <p> 921 * One possible use is if you want to add the same title to the top of all pages by defining a header on a 922 * common parent class like so: 923 * <p class='bcode'> 924 * htmldoc=<ja>@HtmlDoc</ja>( 925 * header={ 926 * <js>"<h1>$R{siteName}</h1>"</js>, 927 * <js>"<h2>$R{resourceTitle}</h2>"</js> 928 * } 929 * ) 930 * </p> 931 * 932 * <p> 933 * Equivalent to calling {@link RestInfoProvider#getSiteName(RestRequest)} with this object. 934 * 935 * @return The localized site name. 936 */ 937 public String getSiteName() { 938 try { 939 return context.getInfoProvider().getSiteName(this); 940 } catch (RestException e) { 941 throw e; 942 } catch (Exception e) { 943 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 944 } 945 } 946 947 /** 948 * Returns the localized resource title. 949 * 950 * <p> 951 * Equivalent to calling {@link RestInfoProvider#getTitle(RestRequest)} with this object. 952 * 953 * @return The localized resource title. 954 */ 955 public String getResourceTitle() { 956 try { 957 return context.getInfoProvider().getTitle(this); 958 } catch (RestException e) { 959 throw e; 960 } catch (Exception e) { 961 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 962 } 963 } 964 965 /** 966 * Returns the localized resource description. 967 * 968 * <p> 969 * Equivalent to calling {@link RestInfoProvider#getDescription(RestRequest)} with this object. 970 * 971 * @return The localized resource description. 972 */ 973 public String getResourceDescription() { 974 try { 975 return context.getInfoProvider().getDescription(this); 976 } catch (RestException e) { 977 throw e; 978 } catch (Exception e) { 979 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 980 } 981 } 982 983 /** 984 * Returns the localized method summary. 985 * 986 * <p> 987 * Equivalent to calling {@link RestInfoProvider#getMethodSummary(Method, RestRequest)} with this object. 988 * 989 * @return The localized method description. 990 */ 991 public String getMethodSummary() { 992 try { 993 return context.getInfoProvider().getMethodSummary(javaMethod, this); 994 } catch (RestException e) { 995 throw e; 996 } catch (Exception e) { 997 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 998 } 999 } 1000 1001 /** 1002 * Returns the localized method description. 1003 * 1004 * <p> 1005 * Equivalent to calling {@link RestInfoProvider#getMethodDescription(Method, RestRequest)} with this object. 1006 * 1007 * @return The localized method description. 1008 */ 1009 public String getMethodDescription() { 1010 try { 1011 return context.getInfoProvider().getMethodDescription(javaMethod, this); 1012 } catch (RestException e) { 1013 throw e; 1014 } catch (Exception e) { 1015 throw new RestException(SC_INTERNAL_SERVER_ERROR, e); 1016 } 1017 } 1018 1019 //-------------------------------------------------------------------------------- 1020 // Other methods 1021 //-------------------------------------------------------------------------------- 1022 1023 /** 1024 * Returns the serializers associated with this request. 1025 * 1026 * <h5 class='section'>See Also:</h5> 1027 * <ul> 1028 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Serializers">Overview > juneau-rest-server > Serializers</a> 1029 * </ul> 1030 * 1031 * @return The serializers associated with this request. 1032 */ 1033 public SerializerGroup getSerializers() { 1034 return restJavaMethod.serializers; 1035 } 1036 1037 /** 1038 * Returns the parsers associated with this request. 1039 * 1040 * <h5 class='section'>See Also:</h5> 1041 * <ul> 1042 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Parsers">Overview > juneau-rest-server > Parsers</a> 1043 * </ul> 1044 * 1045 * @return The parsers associated with this request. 1046 */ 1047 public ParserGroup getParsers() { 1048 return restJavaMethod.parsers; 1049 } 1050 1051 1052 /** 1053 * Returns the method of this request. 1054 * 1055 * <p> 1056 * If <code>allowHeaderParams</code> init parameter is <jk>true</jk>, then first looks for 1057 * <code>&method=xxx</code> in the URL query string. 1058 */ 1059 @Override /* ServletRequest */ 1060 public String getMethod() { 1061 return method; 1062 } 1063 1064 /** 1065 * Returns the HTTP 1.1 method name of the request as an enum. 1066 * 1067 * <p> 1068 * Note that non-RFC2616 method names resolve as {@link HttpMethod#OTHER}. 1069 * 1070 * @return The HTTP method. 1071 */ 1072 public HttpMethod getHttpMethod() { 1073 return HttpMethod.forString(method); 1074 } 1075 1076 @Override /* ServletRequest */ 1077 public int getContentLength() { 1078 return getBody().getContentLength(); 1079 } 1080 1081 int getRawContentLength() { 1082 return super.getContentLength(); 1083 } 1084 1085 /** 1086 * Returns <jk>true</jk> if <code>&plainText=true</code> was specified as a URL parameter. 1087 * 1088 * <p> 1089 * This indicates that the <code>Content-Type</code> of the output should always be set to <js>"text/plain"</js> 1090 * to make it easy to render in a browser. 1091 * 1092 * <p> 1093 * This feature is useful for debugging. 1094 * 1095 * @return <jk>true</jk> if {@code &plainText=true} was specified as a URL parameter 1096 */ 1097 public boolean isPlainText() { 1098 return "true".equals(getQuery().getString("plainText", "false")); 1099 } 1100 1101 /** 1102 * Returns the resource bundle for the request locale. 1103 * 1104 * <h5 class='section'>Example:</h5> 1105 * <p class='bcode'> 1106 * <ja>@RestMethod</ja>(...) 1107 * <jk>public</jk> String sayHello(RestRequest req, <ja>@Query</ja>(<js>"user"</js>) String user) { 1108 * 1109 * <jc>// Get message bundle.</jc> 1110 * MessageBundle mb = req.getMessageBundle(); 1111 * 1112 * <jc>// Return a localized message.</jc> 1113 * <jk>return</jk> mb.getString(<js>"hello.message"</js>, user); 1114 * } 1115 * </p> 1116 * 1117 * <h5 class='section'>Notes:</h5> 1118 * <ul class='spaced-list'> 1119 * <li> 1120 * The {@link MessageBundle} object can also be passed as a parameter on the method. 1121 * </ul> 1122 * 1123 * <h5 class='section'>See Also:</h5> 1124 * <ul> 1125 * <li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_messages} 1126 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMessage(String,Object...)} 1127 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Messages">Overview > juneau-rest-server > Messages</a> 1128 * </ul> 1129 * 1130 * @return 1131 * The resource bundle. 1132 * <br>Never <jk>null</jk>. 1133 */ 1134 public MessageBundle getMessageBundle() { 1135 return context.getMessages().getBundle(getLocale()); 1136 } 1137 1138 /** 1139 * Shortcut method for calling {@link MessageBundle#getString(Locale, String, Object...)} based on the request locale. 1140 * 1141 * @param key The message key. 1142 * @param args Optional {@link MessageFormat}-style arguments. 1143 * @return The localized message. 1144 */ 1145 public String getMessage(String key, Object...args) { 1146 return context.getMessages().getString(getLocale(), key, args); 1147 } 1148 1149 /** 1150 * Returns the resource context handling the request. 1151 * 1152 * <p> 1153 * Can be used to access servlet-init parameters or annotations during requests, such as in calls to 1154 * {@link RestGuard#guard(RestRequest, RestResponse)}.. 1155 * 1156 * @return The resource context handling the request. 1157 */ 1158 public RestContext getContext() { 1159 return context; 1160 } 1161 1162 /** 1163 * Returns the java method handling the request. 1164 * 1165 * <p> 1166 * Can be used to access the method name or method annotations during requests, such as in calls to 1167 * {@link RestGuard#guard(RestRequest, RestResponse)}. 1168 * 1169 * <h5 class='section'>Notes:</h5> 1170 * <ul class='spaced-list'> 1171 * <li> 1172 * This returns <jk>null</jk> when evaluating servlet-level guards since the method has not been resolved at that 1173 * point of execution. 1174 * </ul> 1175 * 1176 * @return The Java method handling the request, or <code>null</code> if the method has not yet been resolved. 1177 */ 1178 public Method getJavaMethod() { 1179 return javaMethod; 1180 } 1181 1182 /** 1183 * Returns the {@link BeanSession} associated with this request. 1184 * 1185 * @return The request bean session. 1186 */ 1187 public BeanSession getBeanSession() { 1188 return beanSession; 1189 } 1190 1191 /** 1192 * Request-level variable resolver session. 1193 * 1194 * <p> 1195 * Used to resolve SVL variables in text. 1196 * 1197 * <h5 class='section'>Example:</h5> 1198 * <p class='bcode'> 1199 * <ja>@RestMethod</ja>(...) 1200 * <jk>public</jk> String sayHello(RestRequest req) { 1201 * 1202 * <jc>// Get var resolver session.</jc> 1203 * VarResolverSession session = getVarResolverSession(); 1204 * 1205 * <jc>// Use it to construct a customized message from a query parameter.</jc> 1206 * <jk>return</jk> session.resolve(<js>"Hello $RQ{user}!"</js>); 1207 * } 1208 * </p> 1209 * 1210 * <h5 class='section'>Notes:</h5> 1211 * <ul class='spaced-list'> 1212 * <li> 1213 * The {@link VarResolverSession} object can also be passed as a parameter on the method. 1214 * </ul> 1215 * 1216 * <h5 class='section'>See Also:</h5> 1217 * <ul> 1218 * <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()} 1219 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.SvlVariables">Overview > juneau-rest-server > SVL Variables</a> 1220 * </ul> 1221 * 1222 * @return The variable resolver for this request. 1223 */ 1224 public VarResolverSession getVarResolverSession() { 1225 if (varSession == null) 1226 varSession = context.getVarResolver().createSession(context.getCallHandler().getSessionObjects(this)); 1227 return varSession; 1228 } 1229 1230 /** 1231 * Returns an instance of a {@link ReaderResource} that represents the contents of a resource text file from the 1232 * classpath. 1233 * 1234 * <p> 1235 * <h5 class='section'>Example:</h5> 1236 * <p class='bcode'> 1237 * <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc> 1238 * <jc>// from the classpath and resolves any SVL variables embedded in it.</jc> 1239 * <ja>@RestMethod</ja>(...) 1240 * <jk>public</jk> String myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) { 1241 * <jk>return</jk> req.getClasspathResourceAsString(file, <jk>true</jk>); 1242 * } 1243 * </p> 1244 * 1245 * <h5 class='section'>See Also:</h5> 1246 * <ul> 1247 * <li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_classpathResourceFinder} 1248 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String, boolean)} 1249 * <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String)} 1250 * </ul> 1251 * 1252 * @param name The name of the resource (i.e. the value normally passed to {@link Class#getResourceAsStream(String)}. 1253 * @param resolveVars 1254 * If <jk>true</jk>, any SVL variables will be 1255 * resolved by the variable resolver returned by {@link #getVarResolverSession()}. 1256 * <br>See {@link RestContext#getVarResolver()} for the list of supported variables. 1257 * @param mediaType The value to set as the <js>"Content-Type"</js> header for this object. 1258 * @return A new reader resource, or <jk>null</jk> if resource could not be found. 1259 * @throws IOException 1260 */ 1261 public ReaderResource getClasspathReaderResource(String name, boolean resolveVars, MediaType mediaType) throws IOException { 1262 String s = context.getClasspathResourceAsString(name, getLocale()); 1263 if (s == null) 1264 return null; 1265 ReaderResourceBuilder b = new ReaderResourceBuilder().mediaType(mediaType).contents(s); 1266 if (resolveVars) 1267 b.varResolver(getVarResolverSession()); 1268 return b.build(); 1269 } 1270 1271 /** 1272 * Same as {@link #getClasspathReaderResource(String, boolean, MediaType)} except uses the resource mime-type map 1273 * constructed using {@link RestContextBuilder#mimeTypes(String...)} to determine the media type. 1274 * 1275 * @param name The name of the resource (i.e. the value normally passed to {@link Class#getResourceAsStream(String)}. 1276 * @param resolveVars 1277 * If <jk>true</jk>, any SVL variables will be 1278 * resolved by the variable resolver returned by {@link #getVarResolverSession()}. 1279 * <br>See {@link RestContext#getVarResolver()} for the list of supported variables. 1280 * @return A new reader resource, or <jk>null</jk> if resource could not be found. 1281 * @throws IOException 1282 */ 1283 public ReaderResource getClasspathReaderResource(String name, boolean resolveVars) throws IOException { 1284 return getClasspathReaderResource(name, resolveVars, MediaType.forString(context.getMediaTypeForName(name))); 1285 } 1286 1287 /** 1288 * Same as {@link #getClasspathReaderResource(String, boolean)} with <code>resolveVars == <jk>false</jk></code> 1289 * 1290 * @param name The name of the resource (i.e. the value normally passed to {@link Class#getResourceAsStream(String)}. 1291 * @return A new reader resource, or <jk>null</jk> if resource could not be found. 1292 * @throws IOException 1293 */ 1294 public ReaderResource getClasspathReaderResource(String name) throws IOException { 1295 return getClasspathReaderResource(name, false, MediaType.forString(context.getMediaTypeForName(name))); 1296 } 1297 1298 /** 1299 * Config file associated with the resource. 1300 * 1301 * <p> 1302 * Returns a config file with session-level variable resolution. 1303 * 1304 * The config file is identified via one of the following: 1305 * <ul> 1306 * <li class='ja'>{@link RestResource#config()} 1307 * <li class='jm'>{@link RestContextBuilder#config(Config)} 1308 * </ul> 1309 * 1310 * <h5 class='section'>Example:</h5> 1311 * <p class='bcode'> 1312 * <ja>@RestMethod</ja>(...) 1313 * <jk>public void</jk> doGet(RestRequest req) { 1314 * 1315 * <jc>// Get config file.</jc> 1316 * Config cf = req.getConfig(); 1317 * 1318 * <jc>// Get simple values from config file.</jc> 1319 * <jk>int</jk> timeout = cf.getInt(<js>"MyResource/timeout"</js>, 10000); 1320 * 1321 * <jc>// Get complex values from config file.</jc> 1322 * MyBean b = cf.getObject(<js>"MyResource/myBean"</js>, MyBean.<jk>class</jk>); 1323 * } 1324 * </p> 1325 * 1326 * <h5 class='section'>Notes:</h5> 1327 * <ul class='spaced-list'> 1328 * <li> 1329 * The {@link Config} object can also be passed as a parameter on the method. 1330 * </ul> 1331 * 1332 * <h5 class='section'>See Also:</h5> 1333 * <ul> 1334 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.ConfigurationFiles">Overview > juneau-rest-server > Configuration Files</a> 1335 * </ul> 1336 * 1337 * @return 1338 * The config file associated with the resource, or <jk>null</jk> if resource does not have a config file 1339 * associated with it. 1340 */ 1341 public Config getConfig() { 1342 if (cf == null) 1343 cf = context.getConfig().resolving(getVarResolverSession()); 1344 return cf; 1345 } 1346 1347 /** 1348 * Returns the widgets used for resolving <js>"$W{...}"</js> string variables. 1349 * 1350 * @return 1351 * The widgets used for resolving <js>"$W{...}"</js> string variables. 1352 * Never <jk>null</jk>. 1353 */ 1354 public Map<String,Widget> getWidgets() { 1355 return restJavaMethod.widgets; 1356 } 1357 1358 @Override /* Object */ 1359 public String toString() { 1360 StringBuilder sb = new StringBuilder("\n").append(getDescription()).append("\n"); 1361 sb.append("---Headers---\n"); 1362 for (Enumeration<String> e = getHeaderNames(); e.hasMoreElements();) { 1363 String h = e.nextElement(); 1364 sb.append("\t").append(h).append(": ").append(getHeader(h)).append("\n"); 1365 } 1366 sb.append("---Default Servlet Headers---\n"); 1367 for (Map.Entry<String,Object> e : context.getDefaultRequestHeaders().entrySet()) { 1368 sb.append("\t").append(e.getKey()).append(": ").append(e.getValue()).append("\n"); 1369 } 1370 if (javaMethod == null) { 1371 sb.append("***init() not called yet!***\n"); 1372 } else if (method.equals("PUT") || method.equals("POST")) { 1373 try { 1374 sb.append("---Body UTF-8---\n"); 1375 sb.append(body.asString()).append("\n"); 1376 sb.append("---Body Hex---\n"); 1377 sb.append(body.asSpacedHex()).append("\n"); 1378 } catch (Exception e1) { 1379 sb.append(e1.getLocalizedMessage()); 1380 context.getLogger().log(WARNING, e1, "Error occurred while trying to read debug input."); 1381 } 1382 } 1383 return sb.toString(); 1384 } 1385 1386 /** 1387 * Logger. 1388 * 1389 * <p> 1390 * Shortcut for calling <code>getContext().getLogger()</code>. 1391 * 1392 * <h5 class='section'>Example:</h5> 1393 * <p class='bcode'> 1394 * <ja>@RestMethod</ja>(...) 1395 * <jk>public void</jk> doGet(RestRequest req) { 1396 * 1397 * req.getLogger().logObjects(<jsf>FINE</jsf>, <js>"Request query parameters = {0}"</js>, req.getQuery()); 1398 * } 1399 * </p> 1400 * 1401 * <h5 class='section'>Notes:</h5> 1402 * <ul class='spaced-list'> 1403 * <li> 1404 * The {@link RestLogger} object can also be passed as a parameter on the method. 1405 * </ul> 1406 * 1407 * <h5 class='section'>See Also:</h5> 1408 * <ul> 1409 * <li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_logger} 1410 * <li class='jac'>{@link org.apache.juneau.rest.RestLogger} 1411 * <li class='jm'>{@link org.apache.juneau.rest.RestServlet#log(Level, String, Object...)} 1412 * <li class='jm'>{@link org.apache.juneau.rest.RestServlet#logObjects(Level, String, Object...)} 1413 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.LoggingAndErrorHandling">Overview > juneau-rest-server > Logging and Error Handling</a> 1414 * </ul> 1415 * 1416 * @return 1417 * The logger associated with the resource context. 1418 * <br>Never <jk>null</jk>. 1419 */ 1420 public RestLogger getLogger() { 1421 return context.getLogger(); 1422 } 1423 1424 void close() { 1425 if (cf != null) { 1426 try { 1427 cf.close(); 1428 } catch (IOException e) { 1429 e.printStackTrace(); 1430 } 1431 } 1432 } 1433 1434 //-------------------------------------------------------------------------------- 1435 // Utility methods 1436 //-------------------------------------------------------------------------------- 1437 1438 /* 1439 * Converts an Accept-Language value entry to a Locale. 1440 */ 1441 private static Locale toLocale(String lang) { 1442 String country = ""; 1443 int i = lang.indexOf('-'); 1444 if (i > -1) { 1445 country = lang.substring(i+1).trim(); 1446 lang = lang.substring(0,i).trim(); 1447 } 1448 return new Locale(lang, country); 1449 } 1450 1451 1452 void setJavaMethod(Method method) { 1453 this.javaMethod = method; 1454 } 1455}