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