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