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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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&lt;Person&gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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&lt;Tag&gt; 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 &gt; juneau-rest-server &gt; 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>"&lt;h1&gt;$R{siteName}&lt;/h1&gt;"</js>,
927    *          <js>"&lt;h2&gt;$R{resourceTitle}&lt;/h2&gt;"</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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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>&amp;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>&amp;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 &amp;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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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 &gt; juneau-rest-server &gt; 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}