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 org.apache.juneau.common.internal.IOUtils.*;
016import static org.apache.juneau.common.internal.ThrowableUtils.*;
017import static org.apache.juneau.httppart.HttpPartType.*;
018import static org.apache.juneau.internal.CollectionUtils.*;
019import static java.lang.Integer.*;
020import static java.util.Optional.*;
021
022import java.io.*;
023import java.lang.reflect.*;
024import java.lang.reflect.Proxy;
025import java.net.*;
026import java.nio.charset.*;
027import java.text.*;
028import java.util.*;
029import jakarta.servlet.*;
030import jakarta.servlet.http.*;
031
032import org.apache.http.*;
033import org.apache.http.message.*;
034import org.apache.juneau.*;
035import org.apache.juneau.assertions.*;
036import org.apache.juneau.common.internal.*;
037import org.apache.juneau.config.*;
038import org.apache.juneau.cp.Messages;
039import org.apache.juneau.dto.swagger.*;
040import org.apache.juneau.dto.swagger.Swagger;
041import org.apache.juneau.http.annotation.Content;
042import org.apache.juneau.http.annotation.FormData;
043import org.apache.juneau.http.annotation.Header;
044import org.apache.juneau.httppart.*;
045import org.apache.juneau.httppart.bean.*;
046import org.apache.juneau.rest.annotation.*;
047import org.apache.juneau.rest.assertions.*;
048import org.apache.juneau.rest.guard.*;
049import org.apache.juneau.rest.httppart.*;
050import org.apache.juneau.rest.logger.*;
051import org.apache.juneau.http.header.*;
052import org.apache.juneau.http.header.Date;
053import org.apache.juneau.http.response.*;
054import org.apache.juneau.http.response.BasicHttpException;
055import org.apache.juneau.rest.staticfile.*;
056import org.apache.juneau.rest.swagger.*;
057import org.apache.juneau.rest.util.*;
058import org.apache.juneau.svl.*;
059import org.apache.juneau.uon.*;
060
061/**
062 * Represents an HTTP request for a REST resource.
063 *
064 * <p>
065 *    The {@link RestRequest} object is an extension of the <l>HttpServletRequest</l> class
066 *    with various built-in convenience methods for use in building REST interfaces.
067 *    It can be accessed by passing it as a parameter on your REST Java method:
068 * </p>
069 *
070 * <p class='bjava'>
071 *    <ja>@RestPost</ja>(...)
072 *    <jk>public</jk> Object myMethod(RestRequest <jv>req</jv>) {...}
073 * </p>
074 *
075 * <p>
076 *    The primary methods on this class are:
077 * </p>
078 * <ul class='javatree'>
079 *    <li class='jc'>{@link RestRequest}
080 *    <ul class='spaced-list'>
081 *       <li>Methods for accessing the request content:
082 *       <ul class='javatreec'>
083 *          <li class='jm'>{@link RestRequest#getContent() getContent()}
084 *          <li class='jm'>{@link RestRequest#getInputStream() getInputStream()}
085 *          <li class='jm'>{@link RestRequest#getReader() getReader()}
086 *       </ul>
087 *       <li>Methods for accessing HTTP parts:
088 *       <ul class='javatreec'>
089 *          <li class='jm'>{@link RestRequest#containsFormParam(String) containsFormParam(String)}
090 *          <li class='jm'>{@link RestRequest#containsHeader(String) containsHeader(String)}
091 *          <li class='jm'>{@link RestRequest#containsQueryParam(String) containsQueryParam(String)}
092 *          <li class='jm'>{@link RestRequest#getHeader(Class) getHeader(Class)}
093 *          <li class='jm'>{@link RestRequest#getHeader(String) getHeader(String)}
094 *          <li class='jm'>{@link RestRequest#getHeaders() getHeaders()}
095 *          <li class='jm'>{@link RestRequest#getFormParam(Class) getFormParam(Class)}
096 *          <li class='jm'>{@link RestRequest#getFormParam(String) getFormParam(String)}
097 *          <li class='jm'>{@link RestRequest#getFormParams() getFormParams()}
098 *          <li class='jm'>{@link RestRequest#getPathParam(Class) getPathParam(Class)}
099 *          <li class='jm'>{@link RestRequest#getPathParam(String) getPathParam(String)}
100 *          <li class='jm'>{@link RestRequest#getPathParams() getPathParams()}
101 *          <li class='jm'>{@link RestRequest#getPathRemainder() getPathRemainder()}
102 *          <li class='jm'>{@link RestRequest#getQueryParam(Class) getQueryParam(Class)}
103 *          <li class='jm'>{@link RestRequest#getQueryParam(String) getQueryParam(String)}
104 *          <li class='jm'>{@link RestRequest#getQueryParams() getQueryParams()}
105 *          <li class='jm'>{@link RestRequest#getQueryString() getQueryString()}
106 *       </ul>
107 *       <li>Methods for localization:
108 *       <ul class='javatreec'>
109 *          <li class='jm'>{@link RestRequest#getLocale() getLocale()}
110 *          <li class='jm'>{@link RestRequest#getMessage(String,Object...) getMessage(String,Object...)}
111 *          <li class='jm'>{@link RestRequest#getMessages() getMessages()}
112 *          <li class='jm'>{@link RestRequest#getTimeZone() getTimeZone()}
113 *       </ul>
114 *       <li>Methods for accessing static files:
115 *       <ul class='javatreec'>
116 *          <li class='jm'>{@link RestRequest#getStaticFiles() getStaticFiles()}
117 *          <li class='jm'>{@link RestRequest#getVarResolverSession() getVarResolverSession()}
118 *       </ul>
119 *       <li>Methods for assertions:
120 *       <ul class='javatreec'>
121 *          <li class='jm'>{@link RestRequest#assertContent() assertContent()}
122 *          <li class='jm'>{@link RestRequest#assertCharset() assertCharset()}
123 *          <li class='jm'>{@link RestRequest#assertFormParam(String) assertFormParam(String)}
124 *          <li class='jm'>{@link RestRequest#assertHeader(String) assertHeader(String)}
125 *          <li class='jm'>{@link RestRequest#assertQueryParam(String) assertQueryParam(String)}
126 *          <li class='jm'>{@link RestRequest#assertRequestLine() assertRequestLine()}
127 *       </ul>
128 *       <li>Other:
129 *       <ul class='javatreec'>
130 *          <li class='jm'>{@link RestRequest#getAttribute(String) getAttribute(String)}
131 *          <li class='jm'>{@link RestRequest#getAttributes() getAttributes()}
132 *          <li class='jm'>{@link RestRequest#getAuthorityPath() getAuthorityPath()}
133 *          <li class='jm'>{@link RestRequest#getBeanSession() getBeanSession()}
134 *          <li class='jm'>{@link RestRequest#getCharset() getCharset()}
135 *          <li class='jm'>{@link RestRequest#getConfig() getConfig()}
136 *          <li class='jm'>{@link RestRequest#getContext() getContext()}
137 *          <li class='jm'>{@link RestRequest#getContextPath() getContextPath()}
138 *          <li class='jm'>{@link RestRequest#getHttpServletRequest() getHttpServletRequest()}
139 *          <li class='jm'>{@link RestRequest#getMethod() getMethod()}
140 *          <li class='jm'>{@link RestRequest#getOpContext() getOpContext()}
141 *          <li class='jm'>{@link RestRequest#getOperationSwagger() getOperationSwagger()}
142 *          <li class='jm'>{@link RestRequest#getPartParserSession() getPartParserSession()}
143 *          <li class='jm'>{@link RestRequest#getPartSerializerSession() getPartSerializerSession()}
144 *          <li class='jm'>{@link RestRequest#getPathInfo() getPathInfo()}
145 *          <li class='jm'>{@link RestRequest#getProtocolVersion() getProtocolVersion()}
146 *          <li class='jm'>{@link RestRequest#getRequest(Class) getRequest(Class)}
147 *          <li class='jm'>{@link RestRequest#getRequestLine() getRequestLine()}
148 *          <li class='jm'>{@link RestRequest#getRequestURI() getRequestURI()}
149 *          <li class='jm'>{@link RestRequest#getRequestURL() getRequestURL()}
150 *          <li class='jm'>{@link RestRequest#getServletPath() getServletPath()}
151 *          <li class='jm'>{@link RestRequest#getSession() getSession()}
152 *          <li class='jm'>{@link RestRequest#getSwagger() getSwagger()}
153 *          <li class='jm'>{@link RestRequest#getUriContext() getUriContext()}
154 *          <li class='jm'>{@link RestRequest#getUriResolver() getUriResolver()}
155 *          <li class='jm'>{@link RestRequest#isDebug() isDebug()}
156 *          <li class='jm'>{@link RestRequest#isPlainText() isPlainText()}
157 *          <li class='jm'>{@link RestRequest#isUserInRole(String) isUserInRole(String)}
158 *          <li class='jm'>{@link RestRequest#setAttribute(String,Object) setAttribute(String,Object)}
159 *          <li class='jm'>{@link RestRequest#setCharset(Charset) setCharset(Charset)}
160 *          <li class='jm'>{@link RestRequest#setDebug() setDebug()}
161 *          <li class='jm'>{@link RestRequest#setException(Throwable) setException(Throwable)}
162 *          <li class='jm'>{@link RestRequest#setNoTrace() setNoTrace()}
163 *       </ul>
164 *    </ul>
165 * </ul>
166 *
167 * <h5 class='section'>See Also:</h5><ul>
168
169 * </ul>
170 */
171@SuppressWarnings({ "unchecked", "unused" })
172public final class RestRequest extends HttpServletRequestWrapper {
173
174   // Constructor initialized.
175   private HttpServletRequest inner;
176   private final RestContext context;
177   private final RestOpContext opContext;
178   private final RequestContent content;
179   private final BeanSession beanSession;
180   private final RequestQueryParams queryParams;
181   private final RequestPathParams pathParams;
182   private final RequestHeaders headers;
183   private final RequestAttributes attrs;
184   private final HttpPartParserSession partParserSession;
185   private final RestSession session;
186
187   // Lazy initialized.
188   private VarResolverSession varSession;
189   private RequestFormParams formParams;
190   private UriContext uriContext;
191   private String authorityPath;
192   private Config config;
193   private Swagger swagger;
194   private Charset charset;
195
196   /**
197    * Constructor.
198    */
199   RestRequest(RestOpContext opContext, RestSession session) throws Exception {
200      super(session.getRequest());
201      this.session = session;
202      this.opContext = opContext;
203
204      inner = session.getRequest();
205      context = session.getContext();
206
207      attrs = new RequestAttributes(this);
208
209      queryParams = new RequestQueryParams(this, session.getQueryParams(), true);
210
211      headers = new RequestHeaders(this, queryParams, false);
212
213      content = new RequestContent(this);
214
215      if (context.isAllowContentParam()) {
216         String b = queryParams.get("content").asString().orElse(null);
217         if (b != null) {
218            headers.set("Content-Type", UonSerializer.DEFAULT.getResponseContentType());
219            content.mediaType(MediaType.UON).parser(UonParser.DEFAULT).content(b.getBytes(UTF8));
220         }
221      }
222
223      pathParams = new RequestPathParams(session, this, true);
224
225      beanSession = opContext.getBeanContext().getSession();
226
227      partParserSession = opContext.getPartParser().getPartSession();
228
229      pathParams.parser(partParserSession);
230
231      queryParams
232         .addDefault(opContext.getDefaultRequestQueryData().getAll())
233         .parser(partParserSession);
234
235      headers
236         .addDefault(opContext.getDefaultRequestHeaders().getAll())
237         .addDefault(context.getDefaultRequestHeaders().getAll())
238         .parser(partParserSession);
239
240      content
241         .encoders(opContext.getEncoders())
242         .parsers(opContext.getParsers())
243         .maxInput(opContext.getMaxInput());
244
245      attrs
246         .addDefault(opContext.getDefaultRequestAttributes())
247         .addDefault(context.getDefaultRequestAttributes());
248
249      if (isDebug())
250         inner = CachingHttpServletRequest.wrap(inner);
251   }
252
253   //-----------------------------------------------------------------------------------------------------------------
254   // Request line.
255   //-----------------------------------------------------------------------------------------------------------------
256
257   /**
258    * Returns the request line of this request.
259    *
260    * @return The request line of this request.
261    */
262   public RequestLine getRequestLine() {
263      String x = inner.getProtocol();
264      int i = x.indexOf('/');
265      int j = x.indexOf('.', i);
266      ProtocolVersion pv = new ProtocolVersion(x.substring(0,i), parseInt(x.substring(i+1,j)), parseInt(x.substring(j+1)));
267      return new BasicRequestLine(inner.getMethod(), inner.getRequestURI(), pv);
268   }
269
270   /**
271    * Returns the protocol version from the request line of this request.
272    *
273    * @return The protocol version from the request line of this request.
274    */
275   public ProtocolVersion getProtocolVersion() {
276      return getRequestLine().getProtocolVersion();
277   }
278
279   //-----------------------------------------------------------------------------------------------------------------
280   // Assertions
281   //-----------------------------------------------------------------------------------------------------------------
282
283   /**
284    * Returns an assertion on the request line returned by {@link #getRequestLine()}.
285    *
286    * <h5 class='section'>Example:</h5>
287    * <p class='bjava'>
288    *    <jc>// Validates the request content contains "foo".</jc>
289    *    <jv>request</jv>
290    *       .assertRequestLine().protocol().minor().is(1);
291    * </p>
292    *
293    * @return A new assertion object.
294    */
295   public FluentRequestLineAssertion<RestRequest> assertRequestLine() {
296      return new FluentRequestLineAssertion<>(getRequestLine(), this);
297   }
298
299   /**
300    * Returns a fluent assertion for the request content.
301    *
302    * <h5 class='section'>Example:</h5>
303    * <p class='bjava'>
304    *    <jc>// Validates the request content contains "foo".</jc>
305    *    <jv>request</jv>
306    *       .assertContent().asString().is(<js>"foo"</js>);
307    * </p>
308    *
309    * @return A new fluent assertion on the content, never <jk>null</jk>.
310    */
311   public FluentRequestContentAssertion<RestRequest> assertContent() {
312      return new FluentRequestContentAssertion<>(getContent(), this);
313   }
314
315   /**
316    * Returns a fluent assertion for the specified header.
317    *
318    * <h5 class='section'>Example:</h5>
319    * <p class='bjava'>
320    *    <jc>// Validates the content type is JSON.</jc>
321    *    <jv>request</jv>
322    *       .assertHeader(<js>"Content-Type"</js>).asString().is(<js>"application/json"</js>);
323    * </p>
324    *
325    * @param name The header name.
326    * @return A new fluent assertion on the parameter, never <jk>null</jk>.
327    */
328   public FluentRequestHeaderAssertion<RestRequest> assertHeader(String name) {
329      return new FluentRequestHeaderAssertion<>(getHeaderParam(name), this);
330   }
331
332   /**
333    * Returns a fluent assertion for the specified query parameter.
334    *
335    * <h5 class='section'>Example:</h5>
336    * <p class='bjava'>
337    *    <jc>// Validates the content type is JSON.</jc>
338    *    <jv>request</jv>
339    *       .assertQueryParam(<js>"foo"</js>).asString().contains(<js>"bar"</js>);
340    * </p>
341    *
342    * @param name The query parameter name.
343    * @return A new fluent assertion on the parameter, never <jk>null</jk>.
344    */
345   public FluentRequestQueryParamAssertion<RestRequest> assertQueryParam(String name) {
346      return new FluentRequestQueryParamAssertion<>(getQueryParam(name), this);
347   }
348
349
350   /**
351    * Returns a fluent assertion for the specified form parameter.
352    *
353    * <h5 class='section'>Example:</h5>
354    * <p class='bjava'>
355    *    <jc>// Validates the content type is JSON.</jc>
356    *    <jv>request</jv>
357    *       .assertFormParam(<js>"foo"</js>).asString().contains(<js>"bar"</js>);
358    * </p>
359    *
360    * @param name The query parameter name.
361    * @return A new fluent assertion on the parameter, never <jk>null</jk>.
362    */
363   public FluentRequestFormParamAssertion<RestRequest> assertFormParam(String name) {
364      return new FluentRequestFormParamAssertion<>(getFormParam(name), this);
365   }
366
367   //-----------------------------------------------------------------------------------------------------------------
368   // Headers
369   //-----------------------------------------------------------------------------------------------------------------
370
371   /**
372    * Request headers.
373    *
374    * <p>
375    * Returns a {@link RequestHeaders} object that encapsulates access to HTTP headers on the request.
376    *
377    * <h5 class='section'>Example:</h5>
378    * <p class='bjava'>
379    *    <ja>@RestPost</ja>(...)
380    *    <jk>public</jk> Object myMethod(RestRequest <jv>req</jv>) {
381    *
382    *       <jc>// Get access to headers.</jc>
383    *       RequestHeaders <jv>headers</jv> = <jv>req</jv>.getRequestHeaders();
384    *
385    *       <jc>// Add a default value.</jc>
386    *       <jv>headers</jv>.addDefault(<js>"ETag"</js>, <jsf>DEFAULT_UUID</jsf>);
387    *
388    *    <jc>// Get a header value as a POJO.</jc>
389    *       UUID etag = <jv>headers</jv>.get(<js>"ETag"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>);
390    *
391    *       <jc>// Get a standard header.</jc>
392    *       Optional&lt;CacheControl&gt; = <jv>headers</jv>.getCacheControl();
393    *    }
394    * </p>
395    *
396    * <h5 class='section'>Notes:</h5><ul>
397    *    <li class='note'>
398    *       This object is modifiable.
399    *    <li class='note'>
400    *       Values are converted from strings using the registered part parser on the resource class.
401    *    <li class='note'>
402    *       The {@link RequestHeaders} object can also be passed as a parameter on the method.
403    *    <li class='note'>
404    *       The {@link Header @Header} annotation can be used to access individual header values.
405    * </ul>
406    *
407    * <h5 class='section'>See Also:</h5><ul>
408    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.HttpParts">HTTP Parts</a>
409    * </ul>
410    *
411    * @return
412    *    The headers on this request.
413    *    <br>Never <jk>null</jk>.
414    */
415   public RequestHeaders getHeaders() {
416      return headers;
417   }
418
419   /**
420    * Returns the last header with a specified name of this message.
421    *
422    * <p>
423    * If there is more than one matching header in the message the last element of <c>getHeaders(String)</c> is returned.
424    * <br>If there is no matching header in the message, an empty request header object is returned.
425    *
426    * <h5 class='section'>Example:</h5>
427    * <p class='bjava'>
428    *    <jc>// Gets a header and throws a BadRequest if it doesn't exist.</jc>
429    *    <jv>request</jv>
430    *       .getHeader(<js>"Foo"</js>)
431    *       .assertValue().exists()
432    *       .get();
433    * </p>
434    *
435    * @param name The header name.
436    * @return The request header object, never <jk>null</jk>.
437    */
438   public RequestHeader getHeaderParam(String name) {
439      return headers.getLast(name);
440   }
441
442   /**
443    * Returns <jk>true</jk> if this request contains the specified header.
444    *
445    * @param name The header name.
446    * @return <jk>true</jk> if this request contains the specified header.
447    */
448   public boolean containsHeader(String name) {
449      return headers.contains(name);
450   }
451
452   /**
453    * Provides the ability to perform fluent-style assertions on the response character encoding.
454    *
455    * <h5 class='section'>Examples:</h5>
456    * <p class='bjava'>
457    *    <jc>// Validates that the response content charset is UTF-8.</jc>
458    *    <jv>request</jv>
459    *       .assertCharset().is(<js>"utf-8"</js>);
460    * </p>
461    *
462    * @return A new fluent assertion object.
463    * @throws BasicHttpException If REST call failed.
464    */
465   public FluentStringAssertion<RestRequest> assertCharset() {
466      return new FluentStringAssertion<>(getCharset().name(), this);
467   }
468
469   /**
470    * Sets the charset to expect on the request content.
471    *
472    * @param value The new value to use for the request content.
473    */
474   public void setCharset(Charset value) {
475      this.charset = value;
476   }
477
478   /**
479    * Returns the charset specified on the <c>Content-Type</c> header, or <js>"UTF-8"</js> if not specified.
480    *
481    * @return The charset to use to decode the request content.
482    */
483   public Charset getCharset() {
484      if (charset == null) {
485         // Determine charset
486         // NOTE:  Don't use super.getCharacterEncoding() because the spec is implemented inconsistently.
487         // Jetty returns the default charset instead of null if the character is not specified on the request.
488         String h = getHeaderParam("Content-Type").orElse(null);
489         if (h != null) {
490            int i = h.indexOf(";charset=");
491            if (i > 0)
492               charset = Charset.forName(h.substring(i+9).trim());
493         }
494         if (charset == null)
495            charset = opContext.getDefaultCharset();
496         if (charset == null)
497            charset = Charset.forName("UTF-8");
498      }
499      return charset;
500   }
501
502   /**
503    * Returns the preferred Locale that the client will accept content in, based on the Accept-Language header.
504    *
505    * <p>
506    * If the client request doesn't provide an <c>Accept-Language</c> header, this method returns the default locale for the server.
507    *
508    * @return The preferred Locale that the client will accept content in.  Never <jk>null</jk>.
509    */
510   @Override
511   public Locale getLocale() {
512      Locale best = inner.getLocale();
513      String h = headers.get("Accept-Language").asString().orElse(null);
514      if (h != null) {
515         StringRanges sr = StringRanges.of(h);
516         float qValue = 0;
517         for (StringRange r : sr.toList()) {
518            if (r.getQValue() > qValue) {
519               best = toLocale(r.getName());
520               qValue = r.getQValue();
521            }
522         }
523      }
524      return best;
525   }
526
527   //-----------------------------------------------------------------------------------------------------------------
528   // Standard headers.
529   //-----------------------------------------------------------------------------------------------------------------
530
531   /**
532    * Returns the request header of the specified type.
533    *
534    * <p>
535    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.Header} annotation
536    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
537    *
538    * <p>
539    * Typically any of the following:
540    * <ul class='javatreec'>
541    *    <li class='jc'>{@link Accept}
542    *    <li class='jc'>{@link AcceptCharset}
543    *    <li class='jc'>{@link AcceptEncoding}
544    *    <li class='jc'>{@link AcceptLanguage}
545    *    <li class='jc'>{@link AcceptRanges}
546    *    <li class='jc'>{@link Authorization}
547    *    <li class='jc'>{@link CacheControl}
548    *    <li class='jc'>{@link ClientVersion}
549    *    <li class='jc'>{@link Connection}
550    *    <li class='jc'>{@link ContentDisposition}
551    *    <li class='jc'>{@link ContentEncoding}
552    *    <li class='jc'>{@link ContentLength}
553    *    <li class='jc'>{@link ContentType}
554    *    <li class='jc'>{@link Date}
555    *    <li class='jc'>{@link Debug}
556    *    <li class='jc'>{@link Expect}
557    *    <li class='jc'>{@link Forwarded}
558    *    <li class='jc'>{@link From}
559    *    <li class='jc'>{@link Host}
560    *    <li class='jc'>{@link IfMatch}
561    *    <li class='jc'>{@link IfModifiedSince}
562    *    <li class='jc'>{@link IfNoneMatch}
563    *    <li class='jc'>{@link IfRange}
564    *    <li class='jc'>{@link IfUnmodifiedSince}
565    *    <li class='jc'>{@link MaxForwards}
566    *    <li class='jc'>{@link NoTrace}
567    *    <li class='jc'>{@link Origin}
568    *    <li class='jc'>{@link Pragma}
569    *    <li class='jc'>{@link ProxyAuthorization}
570    *    <li class='jc'>{@link Range}
571    *    <li class='jc'>{@link Referer}
572    *    <li class='jc'>{@link TE}
573    *    <li class='jc'>{@link Thrown}
574    *    <li class='jc'>{@link Upgrade}
575    *    <li class='jc'>{@link UserAgent}
576    *    <li class='jc'>{@link Warning}
577    * </ul>
578    *
579    * @param <T> The bean type to create.
580    * @param type The bean type to create.
581    * @return The parsed header on the request, never <jk>null</jk>.
582    */
583   public <T> Optional<T> getHeader(Class<T> type) {
584      return headers.get(type);
585   }
586
587   /**
588    * Returns the <c>Time-Zone</c> header value on the request if there is one.
589    *
590    * <p>
591    * Example: <js>"GMT"</js>.
592    *
593    * @return The parsed header on the request, never <jk>null</jk>.
594    */
595   public Optional<TimeZone> getTimeZone() {
596      String tz = headers.get("Time-Zone").asString().orElse(null);
597      if (tz != null)
598         return optional(TimeZone.getTimeZone(tz));
599      return Optional.empty();
600   }
601
602   //-----------------------------------------------------------------------------------------------------------------
603   // Attributes
604   //-----------------------------------------------------------------------------------------------------------------
605
606   /**
607    * Request attributes.
608    *
609    * <p>
610    * Returns a {@link RequestAttributes} object that encapsulates access to attributes on the request.
611    *
612    * <h5 class='section'>Example:</h5>
613    * <p class='bjava'>
614    *    <ja>@RestPost</ja>(...)
615    *    <jk>public</jk> Object myMethod(RestRequest <jv>req</jv>) {
616    *
617    *       <jc>// Get access to attributes.</jc>
618    *       RequestAttributes <jv>attributes</jv> = <jv>req</jv>.getAttributes();
619    *
620    *    <jc>// Get a header value as a POJO.</jc>
621    *       UUID <jv>etag</jv> = <jv>attributes</jv>.get(<js>"ETag"</js>, UUID.<jk>class</jk>);
622    *    }
623    * </p>
624    *
625    * <h5 class='section'>Notes:</h5><ul>
626    *    <li class='note'>
627    *       This object is modifiable.
628    *    <li class='note'>
629    *       Values are converted from strings using the registered part parser on the resource class.
630    *    <li class='note'>
631    *       The {@link RequestAttributes} object can also be passed as a parameter on the method.
632    *    <li class='note'>
633    *       The {@link Attr @Attr} annotation can be used to access individual attribute values.
634    * </ul>
635    *
636    * <h5 class='section'>See Also:</h5><ul>
637    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.HttpParts">HTTP Parts</a>
638    * </ul>
639    *
640    * @return
641    *    The headers on this request.
642    *    <br>Never <jk>null</jk>.
643    */
644   public RequestAttributes getAttributes() {
645      return attrs;
646   }
647
648   /**
649    * Returns the request attribute with the specified name.
650    *
651    * @param name The attribute name.
652    * @return The attribute value, never <jk>null</jk>.
653    */
654   @Override
655   public RequestAttribute getAttribute(String name) {
656      return attrs.get(name);
657   }
658
659   /**
660    * Sets a request attribute.
661    *
662    * @param name The attribute name.
663    * @param value The attribute value.
664    */
665   @Override
666   public void setAttribute(String name, Object value) {
667      attrs.set(name, value);
668   }
669
670   //-----------------------------------------------------------------------------------------------------------------
671   // Query parameters
672   //-----------------------------------------------------------------------------------------------------------------
673
674   /**
675    * Query parameters.
676    *
677    * <p>
678    * Returns a {@link RequestQueryParams} object that encapsulates access to URL GET parameters.
679    *
680    * <p>
681    * Similar to {@link HttpServletRequest#getParameterMap()} but only looks for query parameters in the URL and not form posts.
682    *
683    * <h5 class='section'>Example:</h5>
684    * <p class='bjava'>
685    *    <ja>@RestGet</ja>(...)
686    *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>) {
687    *
688    *       <jc>// Get access to query parameters on the URL.</jc>
689    *       RequestQueryParams <jv>query</jv> = <jv>req</jv>.getQuery();
690    *
691    *       <jc>// Get query parameters converted to various types.</jc>
692    *       <jk>int</jk> <jv>p1/</jv> = <jv>query</jv>.getInteger(<js>"p1"</js>).orElse(<jk>null</jk>);
693    *       String <jv>p2</jv> = <jv>query</jv>.getString(<js>"p2"</js>).orElse(<jk>null</jk>);
694    *       UUID <jv>p3</jv> = <jv>query</jv>.get(<js>"p3"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>);
695    *    }
696    * </p>
697    *
698    * <h5 class='section'>Notes:</h5><ul>
699    *    <li class='note'>
700    *       This object is modifiable.
701    * </ul>
702    *
703    * <h5 class='section'>See Also:</h5><ul>
704    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.HttpParts">HTTP Parts</a>
705    * </ul>
706    *
707    * @return
708    *    The query parameters as a modifiable map.
709    *    <br>Never <jk>null</jk>.
710    */
711   public RequestQueryParams getQueryParams() {
712      return queryParams;
713   }
714
715   /**
716    * Shortcut for calling <c>getRequestQuery().getLast(<jv>name</jv>)</c>.
717    *
718    * @param name The query parameter name.
719    * @return The query parameter, never <jk>null</jk>.
720    */
721   public RequestQueryParam getQueryParam(String name) {
722      return queryParams.get(name);
723   }
724
725   /**
726    * Returns the request query parameter of the specified type.
727    *
728    * <p>
729    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.Query} annotation
730    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
731    *
732    * @param <T> The bean type to create.
733    * @param type The bean type to create.
734    * @return The parsed query parameter on the request, never <jk>null</jk>.
735    */
736   public <T> Optional<T> getQueryParam(Class<T> type) {
737      return queryParams.get(type);
738   }
739
740   /**
741    * Returns <jk>true</jk> if this request contains the specified header.
742    *
743    * @param name The header name.
744    * @return <jk>true</jk> if this request contains the specified header.
745    */
746   public boolean containsQueryParam(String name) {
747      return queryParams.contains(name);
748   }
749
750
751   //-----------------------------------------------------------------------------------------------------------------
752   // Form data parameters
753   //-----------------------------------------------------------------------------------------------------------------
754
755   /**
756    * Form-data.
757    *
758    * <p>
759    * Returns a {@link RequestFormParams} object that encapsulates access to form post parameters.
760    *
761    * <p>
762    * Similar to {@link HttpServletRequest#getParameterMap()}, but only looks for form data in the HTTP content.
763    *
764    * <h5 class='section'>Example:</h5>
765    * <p class='bjava'>
766    *    <ja>@RestPost</ja>(...)
767    *    <jk>public void</jk> doPost(RestRequest <jv>req</jv>) {
768    *
769    *       <jc>// Get access to parsed form data parameters.</jc>
770    *       RequestFormParams <jv>formParams</jv> = <jv>req</jv>.getFormParams();
771    *
772    *       <jc>// Get form data parameters converted to various types.</jc>
773    *       <jk>int</jk> <jv>p1</jv> = <jv>formParams</jv>.get(<js>"p1"</js>).asInteger().orElse(0);
774    *       String <jv>p2</jv> = <jv>formParams</jv>.get(<js>"p2"</js>).asString().orElse(<jk>null</jk>);
775    *       UUID <jv>p3</jv> = <jv>formParams</jv>.get(<js>"p3"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>);
776    *    }
777    * </p>
778    *
779    * <h5 class='section'>Notes:</h5><ul>
780    *    <li class='note'>
781    *       This object is modifiable.
782    *    <li class='note'>
783    *       Values are converted from strings using the registered part parser on the resource class.
784    *    <li class='note'>
785    *       The {@link RequestFormParams} object can also be passed as a parameter on the method.
786    *    <li class='note'>
787    *       The {@link FormData @FormDAta} annotation can be used to access individual form data parameter values.
788    * </ul>
789    *
790    * <h5 class='section'>See Also:</h5><ul>
791    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.HttpParts">HTTP Parts</a>
792    * </ul>
793    *
794    * @return
795    *    The URL-encoded form data from the request.
796    *    <br>Never <jk>null</jk>.
797    * @throws InternalServerError If query parameters could not be parsed.
798    * @see org.apache.juneau.http.annotation.FormData
799    */
800   public RequestFormParams getFormParams() throws InternalServerError {
801      try {
802         if (formParams == null)
803            formParams = new RequestFormParams(this, true).parser(partParserSession);
804         formParams.addDefault(opContext.getDefaultRequestFormData().getAll());
805         return formParams;
806      } catch (Exception e) {
807         throw new InternalServerError(e);
808      }
809   }
810
811   /**
812    * Shortcut for calling <c>getFormData().getString(name)</c>.
813    *
814    * @param name The form data parameter name.
815    * @return The form data parameter value, or <jk>null</jk> if not found.
816    */
817   public RequestFormParam getFormParam(String name) {
818      return getFormParams().get(name);
819   }
820
821   /**
822    * Returns the request form-data parameter of the specified type.
823    *
824    * <p>
825    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.FormData} annotation
826    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
827    *
828    * @param <T> The bean type to create.
829    * @param type The bean type to create.
830    * @return The parsed form-data parameter on the request, never <jk>null</jk>.
831    */
832   public <T> Optional<T> getFormParam(Class<T> type) {
833      return getFormParams().get(type);
834   }
835
836   /**
837    * Returns <jk>true</jk> if this request contains the specified header.
838    *
839    * @param name The header name.
840    * @return <jk>true</jk> if this request contains the specified header.
841    */
842   public boolean containsFormParam(String name) {
843      return getFormParams().contains(name);
844   }
845
846   //-----------------------------------------------------------------------------------------------------------------
847   // Path parameters
848   //-----------------------------------------------------------------------------------------------------------------
849
850   /**
851    * Path parameters.
852    *
853    * <p>
854    * Returns a {@link RequestPathParams} object that encapsulates access to URL path parameters.
855    *
856    * <h5 class='section'>Example:</h5>
857    * <p class='bjava'>
858    *    <ja>@RestGet</ja>(<js>"/{foo}/{bar}/{baz}/*"</js>)
859    *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>) {
860    *
861    *       <jc>// Get access to path data.</jc>
862    *       RequestPathParams <jv>pathParams</jv> = <jv>req</jv>.getPathParams();
863    *
864    *       <jc>// Example URL:  /123/qux/true/quux</jc>
865    *
866    *       <jk>int</jk> <jv>foo</jv> = <jv>pathParams</jv>.get(<js>"foo"</js>).asInteger().orElse(-1);  <jc>// =123</jc>
867    *       String <jv>bar</jv> = <jv>pathParams</jv>.get(<js>"bar"</js>).orElse(<jk>null</jk>);  <jc>// =qux</jc>
868    *       <jk>boolean</jk> <jv>baz</jv> = <jv>pathParams</jv>.get(<js>"baz"</js>).asBoolean().orElse(<jk>false</jk>);  <jc>// =true</jc>
869    *       String <jv>remainder</jv> = <jv>pathParams</jv>.getRemainder().orElse(<jk>null</jk>);  <jc>// =quux</jc>
870    *    }
871    * </p>
872    *
873    * <h5 class='section'>Notes:</h5><ul>
874    *    <li class='note'>
875    *       This object is modifiable.
876    * </ul>
877    *
878    * @return
879    *    The path parameters.
880    *    <br>Never <jk>null</jk>.
881    */
882   public RequestPathParams getPathParams() {
883      return pathParams;
884   }
885
886   /**
887    * Shortcut for calling <c>getPathParams().get(<jv>name</jv>)</c>.
888    *
889    * @param name The path parameter name.
890    * @return The path parameter, never <jk>null</jk>.
891    */
892   public RequestPathParam getPathParam(String name) {
893      return pathParams.get(name);
894   }
895
896   /**
897    * Returns the request path parameter of the specified type.
898    *
899    * <p>
900    * Type must have a name specified via the {@link org.apache.juneau.http.annotation.Path} annotation
901    * and a public constructor that takes in either <c>value</c> or <c>name,value</c> as strings.
902    *
903    * @param <T> The bean type to create.
904    * @param type The bean type to create.
905    * @return The parsed form-data parameter on the request, never <jk>null</jk>.
906    */
907   public <T> Optional<T> getPathParam(Class<T> type) {
908      return pathParams.get(type);
909   }
910
911   /**
912    * Shortcut for calling <c>getPathParams().getRemainder()</c>.
913    *
914    * @return The path remainder value, never <jk>null</jk>.
915    */
916   public RequestPathParam getPathRemainder() {
917      return pathParams.getRemainder();
918   }
919
920   //-----------------------------------------------------------------------------------------------------------------
921   // Content methods
922   //-----------------------------------------------------------------------------------------------------------------
923
924   /**
925    * Request content.
926    *
927    * <p>
928    * Returns a {@link RequestContent} object that encapsulates access to the HTTP request content.
929    *
930    * <h5 class='section'>Example:</h5>
931    * <p class='bjava'>
932    *    <ja>@RestPost</ja>(...)
933    *    <jk>public void</jk> doPost(RestRequest <jv>req</jv>) {
934    *
935    *       <jc>// Convert content to a linked list of Person objects.</jc>
936    *       List&lt;Person&gt; <jv>list</jv> = <jv>req</jv>.getContent().as(LinkedList.<jk>class</jk>, Person.<jk>class</jk>);
937    *       ..
938    *    }
939    * </p>
940    *
941    * <h5 class='section'>Notes:</h5><ul>
942    *    <li class='note'>
943    *       The {@link RequestContent} object can also be passed as a parameter on the method.
944    *    <li class='note'>
945    *       The {@link Content @Content} annotation can be used to access the content as well.
946    * </ul>
947    *
948    * <h5 class='section'>See Also:</h5><ul>
949    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.HttpParts">HTTP Parts</a>
950    * </ul>
951    *
952    * @return
953    *    The content of this HTTP request.
954    *    <br>Never <jk>null</jk>.
955    */
956   public RequestContent getContent() {
957      return content;
958   }
959
960   /**
961    * Returns the HTTP content content as a {@link Reader}.
962    *
963    * <p>
964    * If {@code allowHeaderParams} init parameter is true, then first looks for {@code &content=xxx} in the URL query
965    * string.
966    *
967    * <p>
968    * Automatically handles GZipped input streams.
969    *
970    * <p>
971    * This method is equivalent to calling <c>getContent().getReader()</c>.
972    *
973    * @return The HTTP content content as a {@link Reader}.
974    * @throws IOException If content could not be read.
975    */
976   @Override
977   public BufferedReader getReader() throws IOException {
978      return getContent().getReader();
979   }
980
981   /**
982    * Returns the HTTP content content as an {@link InputStream}.
983    *
984    * <p>
985    * Automatically handles GZipped input streams.
986    *
987    * <p>
988    * This method is equivalent to calling <c>getContent().getInputStream()</c>.
989    *
990    * @return The negotiated input stream.
991    * @throws IOException If any error occurred while trying to get the input stream or wrap it in the GZIP wrapper.
992    */
993   @Override
994   public ServletInputStream getInputStream() throws IOException {
995      return getContent().getInputStream();
996   }
997
998   //-----------------------------------------------------------------------------------------------------------------
999   // URI-related methods
1000   //-----------------------------------------------------------------------------------------------------------------
1001
1002   /**
1003    * Returns the portion of the request URI that indicates the context of the request.
1004    *
1005    * <p>The context path always comes first in a request URI.
1006    * The path starts with a <js>"/"</js> character but does not end with a <js>"/"</js> character.
1007    * For servlets in the default (root) context, this method returns <js>""</js>.
1008    * The container does not decode this string.
1009    *
1010    * @return The context path, never <jk>null</jk>.
1011    * @see HttpServletRequest#getContextPath()
1012    */
1013   @Override
1014   public String getContextPath() {
1015      String cp = context.getUriContext();
1016      return cp == null ? inner.getContextPath() : cp;
1017   }
1018
1019   /**
1020    * Returns the URI authority portion of the request.
1021    *
1022    * @return The URI authority portion of the request.
1023    */
1024   public String getAuthorityPath() {
1025      if (authorityPath == null)
1026         authorityPath = context.getUriAuthority();
1027      if (authorityPath == null) {
1028         String scheme = inner.getScheme();
1029         int port = inner.getServerPort();
1030         StringBuilder sb = new StringBuilder(inner.getScheme()).append("://").append(inner.getServerName());
1031         if (! (port == 80 && "http".equals(scheme) || port == 443 && "https".equals(scheme)))
1032            sb.append(':').append(port);
1033         authorityPath = sb.toString();
1034      }
1035      return authorityPath;
1036   }
1037
1038   /**
1039    * Returns the part of this request's URL that calls the servlet.
1040    *
1041    * <p>
1042    * This path starts with a <js>"/"</js> character and includes either the servlet name or a path to the servlet,
1043    * but does not include any extra path information or a query string.
1044    *
1045    * @return The servlet path, never <jk>null</jk>.
1046    * @see HttpServletRequest#getServletPath()
1047    */
1048   @Override
1049   public String getServletPath() {
1050      String cp = context.getUriContext();
1051      String sp = inner.getServletPath();
1052      return cp == null || ! sp.startsWith(cp) ? sp : sp.substring(cp.length());
1053   }
1054
1055   /**
1056    * Returns the URI context of the request.
1057    *
1058    * <p>
1059    * The URI context contains all the information about the URI of the request, such as the servlet URI, context
1060    * path, etc...
1061    *
1062    * @return The URI context of the request.
1063    */
1064   public UriContext getUriContext() {
1065      if (uriContext == null)
1066         uriContext = UriContext.of(getAuthorityPath(), getContextPath(), getServletPath(), StringUtils.urlEncodePath(inner.getPathInfo()));
1067      return uriContext;
1068   }
1069
1070   /**
1071    * Returns a URI resolver that can be used to convert URIs to absolute or root-relative form.
1072    *
1073    * @param resolution The URI resolution rule.
1074    * @param relativity The relative URI relativity rule.
1075    * @return The URI resolver for this request.
1076    */
1077   public UriResolver getUriResolver(UriResolution resolution, UriRelativity relativity) {
1078      return UriResolver.of(resolution, relativity, getUriContext());
1079   }
1080
1081   /**
1082    * Shortcut for calling {@link #getUriResolver()} using {@link UriResolution#ROOT_RELATIVE} and
1083    * {@link UriRelativity#RESOURCE}
1084    *
1085    * @return The URI resolver for this request.
1086    */
1087   public UriResolver getUriResolver() {
1088      return UriResolver.of(context.getUriResolution(), context.getUriRelativity(), getUriContext());
1089   }
1090
1091   /**
1092    * Returns the URI for this request.
1093    *
1094    * <p>
1095    * Similar to {@link #getRequestURI()} but returns the value as a {@link URI}.
1096    * It also gives you the capability to override the query parameters (e.g. add new query parameters to the existing
1097    * URI).
1098    *
1099    * @param includeQuery If <jk>true</jk> include the query parameters on the request.
1100    * @param addQueryParams Augment the request URI with the specified query parameters.
1101    * @return A new URI.
1102    */
1103   public URI getUri(boolean includeQuery, Map<String,Object> addQueryParams) {
1104      String uri = inner.getRequestURI();
1105      if (includeQuery || addQueryParams != null) {
1106         StringBuilder sb = new StringBuilder(uri);
1107         RequestQueryParams rq = this.queryParams.copy();
1108         if (addQueryParams != null)
1109            for (Map.Entry<String,?> e : addQueryParams.entrySet())
1110               rq.set(e.getKey(), e.getValue());
1111         if (! rq.isEmpty())
1112            sb.append('?').append(rq.asQueryString());
1113         uri = sb.toString();
1114      }
1115      try {
1116         return new URI(uri);
1117      } catch (URISyntaxException e) {
1118         // Shouldn't happen.
1119         throw asRuntimeException(e);
1120      }
1121   }
1122
1123   //-----------------------------------------------------------------------------------------------------------------
1124   // Labels
1125   //-----------------------------------------------------------------------------------------------------------------
1126
1127   /**
1128    * Returns the localized swagger associated with the resource.
1129    *
1130    * <p>
1131    * A shortcut for calling <c>getInfoProvider().getSwagger(request);</c>
1132    *
1133    * <h5 class='section'>Example:</h5>
1134    * <p class='bjava'>
1135    *    <ja>@RestGet</ja>
1136    *    <jk>public</jk> List&lt;Tag&gt; swaggerTags(RestRequest <jv>req</jv>) {
1137    *       <jk>return</jk> <jv>req</jv>.getSwagger().getTags();
1138    *    }
1139    * </p>
1140    *
1141    * <h5 class='section'>Notes:</h5><ul>
1142    *    <li class='note'>
1143    *       The {@link Swagger} object can also be passed as a parameter on the method.
1144    * </ul>
1145    *
1146    * <h5 class='section'>See Also:</h5><ul>
1147    *    <li class='jm'>{@link RestContext.Builder#swaggerProvider(Class)}
1148    *    <li class='jm'>{@link RestContext.Builder#swaggerProvider(SwaggerProvider)}
1149    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.Swagger">Swagger</a>
1150    * </ul>
1151    *
1152    * @return
1153    *    The swagger associated with the resource.
1154    *    <br>Never <jk>null</jk>.
1155    */
1156   public Optional<Swagger> getSwagger() {
1157      return context.getSwagger(getLocale());
1158   }
1159
1160   /**
1161    * Returns the swagger for the Java method invoked.
1162    *
1163    * @return The swagger for the Java method as an {@link Optional}.  Never <jk>null</jk>.
1164    */
1165   public Optional<Operation> getOperationSwagger() {
1166
1167      Optional<Swagger> swagger = getSwagger();
1168      if (! swagger.isPresent())
1169         return Optional.empty();
1170
1171      return ofNullable(swagger.get().getOperation(opContext.getPathPattern(), getMethod().toLowerCase()));
1172   }
1173
1174   //-----------------------------------------------------------------------------------------------------------------
1175   // Other methods
1176   //-----------------------------------------------------------------------------------------------------------------
1177
1178   /**
1179    * Returns the part serializer associated with this request.
1180    *
1181    * @return The part serializer associated with this request.
1182    */
1183   public HttpPartParserSession getPartParserSession() {
1184      return partParserSession;
1185   }
1186
1187   /**
1188    * Returns the HTTP method of this request.
1189    *
1190    * <p>
1191    * If <c>allowHeaderParams</c> init parameter is <jk>true</jk>, then first looks for
1192    * <c>&amp;method=xxx</c> in the URL query string.
1193    *
1194    * @return The HTTP method of this request.
1195    */
1196   @Override
1197   public String getMethod() {
1198      return session.getMethod();
1199   }
1200
1201   /**
1202    * Returns <jk>true</jk> if <c>&amp;plainText=true</c> was specified as a URL parameter.
1203    *
1204    * <p>
1205    * This indicates that the <c>Content-Type</c> of the output should always be set to <js>"text/plain"</js>
1206    * to make it easy to render in a browser.
1207    *
1208    * <p>
1209    * This feature is useful for debugging.
1210    *
1211    * @return <jk>true</jk> if {@code &amp;plainText=true} was specified as a URL parameter
1212    */
1213   public boolean isPlainText() {
1214      return "true".equals(queryParams.get("plainText").asString().orElse("false"));
1215   }
1216
1217   /**
1218    * Returns the resource bundle for the request locale.
1219    *
1220    * <h5 class='section'>Example:</h5>
1221    * <p class='bjava'>
1222    *    <ja>@RestGet</ja>
1223    *    <jk>public</jk> String hello(RestRequest <jv>req</jv>, <ja>@Query</ja>(<js>"user"</js>) String <jv>user</jv>) {
1224    *
1225    *       <jc>// Return a localized message.</jc>
1226    *       <jk>return</jk> <jv>req</jv>.getMessages().getString(<js>"hello.message"</js>, <jv>user</jv>);
1227    *    }
1228    * </p>
1229    *
1230    * <h5 class='section'>Notes:</h5><ul>
1231    *    <li class='note'>
1232    *       The {@link Messages} object can also be passed as a parameter on the method.
1233    * </ul>
1234    *
1235    * <h5 class='section'>See Also:</h5><ul>
1236    *    <li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMessage(String,Object...)}
1237    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.LocalizedMessages">Localized Messages</a>
1238    * </ul>
1239    *
1240    * @return
1241    *    The resource bundle.
1242    *    <br>Never <jk>null</jk>.
1243    */
1244   public Messages getMessages() {
1245      return context.getMessages().forLocale(getLocale());
1246   }
1247
1248   /**
1249    * Shortcut method for calling {@link RestRequest#getMessages()} and {@link Messages#getString(String,Object...)}.
1250    *
1251    * @param key The message key.
1252    * @param args Optional {@link MessageFormat}-style arguments.
1253    * @return The localized message.
1254    */
1255   public String getMessage(String key, Object...args) {
1256      return getMessages().getString(key, args);
1257   }
1258
1259   /**
1260    * Returns the resource context handling the request.
1261    *
1262    * <p>
1263    * Can be used to access servlet-init parameters or annotations during requests, such as in calls to
1264    * {@link RestGuard#guard(RestRequest, RestResponse)}..
1265    *
1266    * @return The resource context handling the request.
1267    */
1268   public RestContext getContext() {
1269      return context;
1270   }
1271
1272   /**
1273    * Returns access to the inner {@link RestOpContext} of this method.
1274    *
1275    * @return The {@link RestOpContext} of this method.  May be <jk>null</jk> if method has not yet been found.
1276    */
1277   public RestOpContext getOpContext() {
1278      return opContext;
1279   }
1280
1281   /**
1282    * Returns the {@link BeanSession} associated with this request.
1283    *
1284    * @return The request bean session.
1285    */
1286   public BeanSession getBeanSession() {
1287      return beanSession;
1288   }
1289
1290   /**
1291    * Returns <jk>true</jk> if debug mode is enabled.
1292    *
1293    * 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.
1294    *
1295    * @return <jk>true</jk> if debug mode is enabled.
1296    */
1297   public boolean isDebug() {
1298      return getAttribute("Debug").as(Boolean.class).orElse(false);
1299   }
1300
1301   /**
1302    * Sets the <js>"Exception"</js> attribute to the specified throwable.
1303    *
1304    * <p>
1305    * This exception is used by {@link CallLogger} for logging purposes.
1306    *
1307    * @param t The attribute value.
1308    * @return This object.
1309    */
1310   public RestRequest setException(Throwable t) {
1311      setAttribute("Exception", t);
1312      return this;
1313   }
1314
1315   /**
1316    * Sets the <js>"NoTrace"</js> attribute to the specified boolean.
1317    *
1318    * <p>
1319    * This flag is used by {@link CallLogger} and tells it not to log the current request.
1320    *
1321    * @param b The attribute value.
1322    * @return This object.
1323    */
1324   public RestRequest setNoTrace(Boolean b) {
1325      setAttribute("NoTrace", b);
1326      return this;
1327   }
1328
1329   /**
1330    * Shortcut for calling <c>setNoTrace(<jk>true</jk>)</c>.
1331    *
1332    * @return This object.
1333    */
1334   public RestRequest setNoTrace() {
1335      return setNoTrace(true);
1336   }
1337
1338   /**
1339    * Sets the <js>"Debug"</js> attribute to the specified boolean.
1340    *
1341    * <p>
1342    * This flag is used by {@link CallLogger} to help determine how a request should be logged.
1343    *
1344    * @param b The attribute value.
1345    * @return This object.
1346    * @throws IOException If content could not be cached.
1347    */
1348   public RestRequest setDebug(Boolean b) throws IOException {
1349      setAttribute("Debug", b);
1350      if (b)
1351         inner = CachingHttpServletRequest.wrap(inner);
1352      return this;
1353   }
1354
1355   /**
1356    * Shortcut for calling <c>setDebug(<jk>true</jk>)</c>.
1357    *
1358    * @return This object.
1359    * @throws IOException If content could not be cached.
1360    */
1361   public RestRequest setDebug() throws IOException {
1362      return setDebug(true);
1363   }
1364
1365   /**
1366    * Request-level variable resolver session.
1367    *
1368    * <p>
1369    * Used to resolve SVL variables in text.
1370    *
1371    * <h5 class='section'>Example:</h5>
1372    * <p class='bjava'>
1373    *    <ja>@RestGet</ja>
1374    *    <jk>public</jk> String hello(RestRequest <jv>req</jv>) {
1375    *
1376    *       <jc>// Get var resolver session.</jc>
1377    *       VarResolverSession <jv>session</jv> = getVarResolverSession();
1378    *
1379    *       <jc>// Use it to construct a customized message from a query parameter.</jc>
1380    *       <jk>return</jk> <jv>session</jv>.resolve(<js>"Hello $RQ{user}!"</js>);
1381    *    }
1382    * </p>
1383    *
1384    * <h5 class='section'>Notes:</h5><ul>
1385    *    <li class='note'>
1386    *       The {@link VarResolverSession} object can also be passed as a parameter on the method.
1387    * </ul>
1388    *
1389    * <h5 class='section'>See Also:</h5><ul>
1390    *    <li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
1391    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.SvlVariables">SVL Variables</a>
1392    * </ul>
1393    *
1394    * @return The variable resolver for this request.
1395    */
1396   public VarResolverSession getVarResolverSession() {
1397      if (varSession == null)
1398         varSession = context
1399            .getVarResolver()
1400            .createSession(session.getBeanStore())
1401            .bean(RestRequest.class, this)
1402            .bean(RestSession.class, session);
1403      return varSession;
1404   }
1405
1406   /**
1407    * Returns the static files registered on the REST resource context object.
1408    *
1409    * <p>
1410    * Used to retrieve localized files to be served up as static files through the REST API.
1411    *
1412    * @return This object.
1413    */
1414   public StaticFiles getStaticFiles() {
1415      return context.getStaticFiles();
1416   }
1417
1418   /**
1419    * Config file associated with the resource.
1420    *
1421    * <p>
1422    * Returns a config file with session-level variable resolution.
1423    *
1424    * The config file is identified via one of the following:
1425    * <ul class='javatree'>
1426    *    <li class='ja'>{@link Rest#config()}
1427    *    <li class='jm'>{@link RestContext.Builder#config(Config)}
1428    * </ul>
1429    *
1430    * <h5 class='section'>Example:</h5>
1431    * <p class='bjava'>
1432    *    <ja>@RestGet</ja>(...)
1433    *    <jk>public void</jk> doGet(RestRequest <jv>req</jv>) {
1434    *
1435    *       <jc>// Get config file.</jc>
1436    *       Config <jv>config</jv> = <jv>req</jv>.getConfig();
1437    *
1438    *       <jc>// Get simple values from config file.</jc>
1439    *       <jk>int</jk> <jv>timeout</jv> = <jv>config</jv>.get(<js>"MyResource/timeout"</js>).asInteger().orElse(=10000);
1440    *
1441    *       <jc>// Get complex values from config file.</jc>
1442    *       MyBean <jv>bean</jv> = <jv>config</jv>.get(<js>"MyResource/myBean"</js>).as(MyBean.<jk>class</jk>).orElse(<jk>null</jk>);
1443    *    }
1444    * </p>
1445    *
1446    * <h5 class='section'>Notes:</h5><ul>
1447    *    <li class='note'>
1448    *       The {@link Config} object can also be passed as a parameter on the method.
1449    * </ul>
1450    *
1451    * <h5 class='section'>See Also:</h5><ul>
1452    *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.ConfigurationFiles">Configuration Files</a>
1453    * </ul>
1454    *
1455    * @return
1456    *    The config file associated with the resource, or <jk>null</jk> if resource does not have a config file
1457    *    associated with it.
1458    */
1459   public Config getConfig() {
1460      if (config == null)
1461         config = context.getConfig().resolving(getVarResolverSession());
1462      return config;
1463   }
1464
1465   /**
1466    * Creates a proxy interface to retrieve HTTP parts of this request as a proxy bean.
1467    *
1468    * <h5 class='section'>Examples:</h5>
1469    * <p class='bjava'>
1470    *    <ja>@RestPost</ja>(<js>"/mypath/{p1}/{p2}/*"</js>)
1471    *    <jk>public void</jk> myMethod(<ja>@Request</ja> MyRequest <jv>requestBean</jv>) {...}
1472    *
1473    *    <jk>public interface</jk> MyRequest {
1474    *
1475    *       <ja>@Path</ja> <jc>// Path variable name inferred from getter.</jc>
1476    *       String getP1();
1477    *
1478    *       <ja>@Path</ja>(<js>"p2"</js>)
1479    *       String getX();
1480    *
1481    *       <ja>@Path</ja>(<js>"/*"</js>)
1482    *       String getRemainder();
1483    *
1484    *       <ja>@Query</ja>
1485    *       String getQ1();
1486    *
1487    *    <jc>// Schema-based query parameter:  Pipe-delimited lists of comma-delimited lists of integers.</jc>
1488    *       <ja>@Query</ja>(
1489    *          collectionFormat=<js>"pipes"</js>
1490    *          items=<ja>@Items</ja>(
1491    *             items=<ja>@SubItems</ja>(
1492    *                collectionFormat=<js>"csv"</js>
1493    *                type=<js>"integer"</js>
1494    *             )
1495    *          )
1496    *       )
1497    *       <jk>int</jk>[][] getQ3();
1498    *
1499    *       <ja>@Header</ja>(<js>"*"</js>)
1500    *       Map&lt;String,Object&gt; getHeaders();
1501    * </p>
1502    *
1503    * @param <T> The request bean interface to instantiate.
1504    * @param c The request bean interface to instantiate.
1505    * @return A new request bean proxy for this REST request.
1506    */
1507   public <T> T getRequest(Class<T> c) {
1508      return getRequest(RequestBeanMeta.create(c, getContext().getAnnotations()));
1509   }
1510
1511   /**
1512    * Same as {@link #getRequest(Class)} but used on pre-instantiated {@link RequestBeanMeta} objects.
1513    *
1514    * @param <T> The request bean interface to instantiate.
1515    * @param rbm The metadata about the request bean interface to create.
1516    * @return A new request bean proxy for this REST request.
1517    */
1518   public <T> T getRequest(final RequestBeanMeta rbm) {
1519      try {
1520         Class<T> c = (Class<T>)rbm.getClassMeta().getInnerClass();
1521         final BeanSession bs = getBeanSession();
1522         final BeanMeta<T> bm = bs.getBeanMeta(c);
1523         return (T)Proxy.newProxyInstance(
1524            c.getClassLoader(),
1525            new Class[] { c },
1526            (InvocationHandler) (proxy, method, args) -> {
1527                  RequestBeanPropertyMeta pm = rbm.getProperty(method.getName());
1528                  if (pm != null) {
1529                     HttpPartParserSession pp = pm.getParser(getPartParserSession());
1530                     HttpPartSchema schema = pm.getSchema();
1531                     String name = pm.getPartName();
1532                     ClassMeta<?> type = bs.getClassMeta(method.getGenericReturnType());
1533                     HttpPartType pt = pm.getPartType();
1534                     if (pt == HttpPartType.BODY)
1535                        return getContent().setSchema(schema).as(type);
1536                     if (pt == QUERY)
1537                        return getQueryParam(name).parser(pp).schema(schema).as(type).orElse(null);
1538                     if (pt == FORMDATA)
1539                        return getFormParam(name).parser(pp).schema(schema).as(type).orElse(null);
1540                     if (pt == HEADER)
1541                        return getHeaderParam(name).parser(pp).schema(schema).as(type).orElse(null);
1542                     if (pt == PATH)
1543                        return getPathParam(name).parser(pp).schema(schema).as(type).orElse(null);
1544                  }
1545                  return null;
1546                });
1547      } catch (Exception e) {
1548         throw asRuntimeException(e);
1549      }
1550   }
1551
1552   /* Called by RestSession.finish() */
1553   void close() {
1554      if (config != null) {
1555         try {
1556            config.close();
1557         } catch (IOException e) {
1558            e.printStackTrace();
1559         }
1560      }
1561   }
1562
1563   /**
1564    * Returns the wrapped servlet request.
1565    *
1566    * @return The wrapped servlet request.
1567    */
1568   public HttpServletRequest getHttpServletRequest() {
1569      return inner;
1570   }
1571
1572   /**
1573    * Returns the part serializer session for this request.
1574    *
1575    * @return The part serializer session for this request.
1576    */
1577   public HttpPartSerializerSession getPartSerializerSession() {
1578      return opContext.getPartSerializer().getPartSession();
1579   }
1580
1581   @Override /* Object */
1582   public String toString() {
1583      StringBuilder sb = new StringBuilder("\n").append(getRequestLine()).append("\n");
1584      sb.append("---Headers---\n");
1585      getHeaders().forEach(x -> sb.append("\t").append(x).append("\n"));
1586      String m = getMethod();
1587      if (m.equals("PUT") || m.equals("POST")) {
1588         try {
1589            sb.append("---Content UTF-8---\n");
1590            sb.append(content.asString()).append("\n");
1591            sb.append("---Content Hex---\n");
1592            sb.append(content.asSpacedHex()).append("\n");
1593         } catch (Exception e1) {
1594            sb.append(e1.getLocalizedMessage());
1595         }
1596      }
1597      return sb.toString();
1598   }
1599
1600   //-----------------------------------------------------------------------------------------------------------------
1601   // Utility methods
1602   //-----------------------------------------------------------------------------------------------------------------
1603
1604   /*
1605    * Converts an Accept-Language value entry to a Locale.
1606    */
1607   private static Locale toLocale(String lang) {
1608      String country = "";
1609      int i = lang.indexOf('-');
1610      if (i > -1) {
1611         country = lang.substring(i+1).trim();
1612         lang = lang.substring(0,i).trim();
1613      }
1614      return new Locale(lang, country);
1615   }
1616}