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