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 javax.servlet.http.HttpServletResponse.*;
016import static org.apache.juneau.internal.CollectionUtils.*;
017import static org.apache.juneau.internal.IOUtils.*;
018import static org.apache.juneau.internal.StringUtils.*;
019import static org.apache.juneau.rest.util.RestUtils.*;
020import static org.apache.juneau.rest.HttpRuntimeException.*;
021import static org.apache.juneau.FormattedIllegalArgumentException.*;
022
023import java.io.*;
024import java.lang.reflect.Method;
025import java.nio.charset.*;
026import java.time.*;
027import java.util.*;
028import java.util.concurrent.*;
029import java.util.concurrent.atomic.*;
030import java.util.stream.*;
031
032import javax.activation.*;
033import javax.servlet.*;
034import javax.servlet.http.*;
035
036import org.apache.juneau.*;
037import org.apache.juneau.annotation.*;
038import org.apache.juneau.config.*;
039import org.apache.juneau.encoders.*;
040import org.apache.juneau.html.*;
041import org.apache.juneau.html.annotation.*;
042import org.apache.juneau.http.*;
043import org.apache.juneau.http.StreamResource;
044import org.apache.juneau.http.annotation.*;
045import org.apache.juneau.http.annotation.Body;
046import org.apache.juneau.http.annotation.FormData;
047import org.apache.juneau.http.annotation.HasFormData;
048import org.apache.juneau.http.annotation.HasQuery;
049import org.apache.juneau.http.annotation.Header;
050import org.apache.juneau.http.annotation.Path;
051import org.apache.juneau.http.annotation.Query;
052import org.apache.juneau.http.annotation.Response;
053import org.apache.juneau.httppart.*;
054import org.apache.juneau.httppart.bean.*;
055import org.apache.juneau.json.*;
056import org.apache.juneau.jsonschema.*;
057import org.apache.juneau.msgpack.*;
058import org.apache.juneau.oapi.*;
059import org.apache.juneau.parser.*;
060import org.apache.juneau.plaintext.*;
061import org.apache.juneau.reflect.*;
062import org.apache.juneau.remote.*;
063import org.apache.juneau.rest.annotation.*;
064import org.apache.juneau.rest.converters.*;
065import org.apache.juneau.http.exception.*;
066import org.apache.juneau.rest.reshandlers.*;
067import org.apache.juneau.rest.util.*;
068import org.apache.juneau.rest.vars.*;
069import org.apache.juneau.serializer.*;
070import org.apache.juneau.soap.*;
071import org.apache.juneau.svl.*;
072import org.apache.juneau.uon.*;
073import org.apache.juneau.urlencoding.*;
074import org.apache.juneau.utils.*;
075import org.apache.juneau.xml.*;
076import org.apache.juneau.xmlschema.XmlSchemaDocSerializer;
077
078/**
079 * Contains all the configuration on a REST resource and the entry points for handling REST calls.
080 *
081 * <ul class='seealso'>
082 *    <li class='link'>{@doc juneau-rest-server.RestContext}
083 * </ul>
084 */
085@ConfigurableContext(nocache=true)
086public final class RestContext extends BeanContext {
087
088   //-------------------------------------------------------------------------------------------------------------------
089   // Configurable properties
090   //-------------------------------------------------------------------------------------------------------------------
091
092   static final String PREFIX = "RestContext";
093
094   /**
095    * Configuration property:  Allow body URL parameter.
096    *
097    * <h5 class='section'>Property:</h5>
098    * <ul class='spaced-list'>
099    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_allowBodyParam REST_allowBodyParam}
100    *    <li><b>Name:</b>  <js>"RestContext.allowBodyParam.b"</js>
101    *    <li><b>Data type:</b>  <jk>boolean</jk>
102    *    <li><b>System property:</b>  <c>RestContext.allowBodyParam</c>
103    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_ALLOWBODYPARAM</c>
104    *    <li><b>Default:</b>  <jk>true</jk>
105    *    <li><b>Session property:</b>  <jk>false</jk>
106    *    <li><b>Annotations:</b>
107    *       <ul>
108    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#allowBodyParam()}
109    *       </ul>
110    *    <li><b>Methods:</b>
111    *       <ul>
112    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#allowBodyParam(boolean)}
113    *       </ul>
114    * </ul>
115    *
116    * <h5 class='section'>Description:</h5>
117    * <p>
118    * When enabled, the HTTP body content on PUT and POST requests can be passed in as text using the <js>"body"</js>
119    * URL parameter.
120    * <br>
121    * For example:
122    * <p class='bcode w800'>
123    *  ?body=(name='John%20Smith',age=45)
124    * </p>
125    *
126    * <h5 class='section'>Example:</h5>
127    * <p class='bcode w800'>
128    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
129    *    <ja>@Rest</ja>(allowBodyParam=<js>"$C{REST/allowBodyParam,false}"</js>)
130    *    <jk>public class</jk> MyResource {
131    *
132    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
133    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
134    *
135    *          <jc>// Using method on builder.</jc>
136    *          builder.allowBodyParam(<jk>false</jk>);
137    *
138    *          <jc>// Same, but using property.</jc>
139    *          builder.set(<jsf>REST_allowBodyParam</jsf>, <jk>false</jk>);
140    *       }
141    *
142    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
143    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
144    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
145    *          builder.allowBodyParam(<jk>false</jk>);
146    *       }
147    *    }
148    * </p>
149    *
150    * <ul class='notes'>
151    *    <li>
152    *       <js>'body'</js> parameter name is case-insensitive.
153    *    <li>
154    *       Useful for debugging PUT and POST methods using only a browser.
155    * </ul>
156    */
157   public static final String REST_allowBodyParam = PREFIX + ".allowBodyParam.b";
158
159   /**
160    * Configuration property:  Allowed header URL parameters.
161    *
162    * <h5 class='section'>Property:</h5>
163    * <ul class='spaced-list'>
164    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_allowedHeaderParams REST_allowedHeaderParams}
165    *    <li><b>Name:</b>  <js>"RestContext.allowedHeaderParams.s"</js>
166    *    <li><b>Data type:</b>  <c>String</c> (comma-delimited)
167    *    <li><b>System property:</b>  <c>RestContext.allowedHeaderParams</c>
168    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_ALLOWHEADERPARAMS</c>
169    *    <li><b>Default:</b>  <js>"Accept,Content-Type"</js>
170    *    <li><b>Session property:</b>  <jk>false</jk>
171    *    <li><b>Annotations:</b>
172    *       <ul>
173    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#allowedHeaderParams()}
174    *       </ul>
175    *    <li><b>Methods:</b>
176    *       <ul>
177    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#allowedHeaderParams(String)}
178    *       </ul>
179    * </ul>
180    *
181    * <h5 class='section'>Description:</h5>
182    * <p>
183    * When specified, allows headers such as <js>"Accept"</js> and <js>"Content-Type"</js> to be passed in as URL query
184    * parameters.
185    * <br>
186    * For example:
187    * <p class='bcode w800'>
188    *  ?Accept=text/json&amp;Content-Type=text/json
189    * </p>
190    *
191    * <h5 class='section'>Example:</h5>
192    * <p class='bcode w800'>
193    *    <jc>// Option #1 - Defined via annotation.</jc>
194    *    <ja>@Rest</ja>(allowedHeaderParams=<js>"Accept,Content-Type"</js>)
195    *    <jk>public class</jk> MyResource {
196    *
197    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
198    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
199    *
200    *          <jc>// Using method on builder.</jc>
201    *          builder.allowedHeaderParams(<js>"Accept,Content-Type"</js>);
202    *
203    *          <jc>// Same, but using property.</jc>
204    *          builder.set(<jsf>REST_allowedHeaderParams</jsf>, <js>"Accept,Content-Type"</js>);
205    *       }
206    *
207    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
208    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
209    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
210    *          builder.allowedHeaderParams(<js>"Accept,Content-Type"</js>);
211    *       }
212    *    }
213    * </p>
214    *
215    * <ul class='notes'>
216    *    <li>
217    *       Useful for debugging REST interface using only a browser so that you can quickly simulate header values
218    *       in the URL bar.
219    *    <li>
220    *       Header names are case-insensitive.
221    *    <li>
222    *       Use <js>"*"</js> to allow any headers to be specified as URL parameters.
223    *    <li>
224    *       Use <js>"NONE"</js> (case insensitive) to suppress inheriting a value from a parent class.
225    * </ul>
226    */
227   public static final String REST_allowedHeaderParams = PREFIX + ".allowedHeaderParams.s";
228
229   /**
230    * Configuration property:  Allowed method headers.
231    *
232    * <h5 class='section'>Property:</h5>
233    * <ul class='spaced-list'>
234    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_allowedMethodHeaders REST_allowedMethodHeaders}
235    *    <li><b>Name:</b>  <js>"RestContext.allowedMethodHeaders.s"</js>
236    *    <li><b>Data type:</b>  <c>String</c> (comma-delimited)
237    *    <li><b>System property:</b>  <c>RestContext.allowedMethodHeaders</c>
238    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_ALLOWEDMETHODHEADERS</c>
239    *    <li><b>Default:</b>  empty string
240    *    <li><b>Session property:</b>  <jk>false</jk>
241    *    <li><b>Annotations:</b>
242    *       <ul>
243    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#allowedMethodHeaders()}
244    *       </ul>
245    *    <li><b>Methods:</b>
246    *       <ul>
247    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#allowedMethodHeaders(String)}
248    *       </ul>
249    * </ul>
250    *
251    * <h5 class='section'>Description:</h5>
252    * <p>
253    * A comma-delimited list of HTTP method names that are allowed to be passed as values in an <c>X-Method</c> HTTP header
254    * to override the real HTTP method name.
255    * <p>
256    * Allows you to override the actual HTTP method with a simulated method.
257    * <br>For example, if an HTTP Client API doesn't support <c>PATCH</c> but does support <c>POST</c> (because
258    * <c>PATCH</c> is not part of the original HTTP spec), you can add a <c>X-Method: PATCH</c> header on a normal
259    * <c>HTTP POST /foo</c> request call which will make the HTTP call look like a <c>PATCH</c> request in any of the REST APIs.
260    *
261    * <h5 class='section'>Example:</h5>
262    * <p class='bcode w800'>
263    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
264    *    <ja>@Rest</ja>(allowedMethodHeaders=<js>"PATCH"</js>)
265    *    <jk>public class</jk> MyResource {
266    *
267    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
268    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
269    *
270    *          <jc>// Using method on builder.</jc>
271    *          builder.allowedMethodHeaders(<js>"PATCH"</js>);
272    *
273    *          <jc>// Same, but using property.</jc>
274    *          builder.set(<jsf>REST_allowedMethodHeaders</jsf>, <js>"PATCH"</js>);
275    *       }
276    *
277    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
278    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
279    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
280    *          builder.allowedMethodHeaders(<js>"PATCH"</js>);
281    *       }
282    *    }
283    * </p>
284    *
285    * <ul class='notes'>
286    *    <li>
287    *       Method names are case-insensitive.
288    *    <li>
289    *       Use <js>"*"</js> to represent all methods.
290    *    <li>
291    *       Use <js>"NONE"</js> (case insensitive) to suppress inheriting a value from a parent class.
292    * </ul>
293    */
294   public static final String REST_allowedMethodHeaders = PREFIX + ".allowedMethodHeaders.s";
295
296   /**
297    * Configuration property:  Allowed method URL parameters.
298    *
299    * <h5 class='section'>Property:</h5>
300    * <ul class='spaced-list'>
301    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_allowedMethodParams REST_allowedMethodParams}
302    *    <li><b>Name:</b>  <js>"RestContext.allowedMethodParams.s"</js>
303    *    <li><b>Data type:</b>  <c>String</c> (comma-delimited)
304    *    <li><b>System property:</b>  <c>RestContext.allowedMethodParams</c>
305    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_ALLOWEDMETHODPARAMS</c>
306    *    <li><b>Default:</b>  <js>"HEAD,OPTIONS"</js>
307    *    <li><b>Session property:</b>  <jk>false</jk>
308    *    <li><b>Annotations:</b>
309    *       <ul>
310    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#allowedMethodParams()}
311    *       </ul>
312    *    <li><b>Methods:</b>
313    *       <ul>
314    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#allowedMethodParams(String)}
315    *       </ul>
316    * </ul>
317    *
318    * <h5 class='section'>Description:</h5>
319    * <p>
320    * When specified, the HTTP method can be overridden by passing in a <js>"method"</js> (case-insensitive) URL parameter on a regular
321    * GET request.
322    * <br>
323    * For example:
324    * <p class='bcode w800'>
325    *  /myservlet/myendpoint?method=OPTIONS
326    * </p>
327    * <p>
328    *    Useful in cases where you want to simulate a non-GET request in a browser by simply adding a parameter.
329    *    <br>Also useful if you want to construct hyperlinks to non-GET REST endpoints such as links to <c>OPTIONS</c>
330    * pages.
331    *
332    * <p>
333    * Note that per the {@doc RFC2616.section9 HTTP specification}, special care should
334    * be taken when allowing non-safe (<c>POST</c>, <c>PUT</c>, <c>DELETE</c>) methods to be invoked through GET requests.
335    *
336    *
337    * <h5 class='section'>Example:</h5>
338    * <p class='bcode w800'>
339    *    <jc>// Option #1 - Defined via annotation.</jc>
340    *    <ja>@Rest</ja>(allowedMethodParams=<js>"HEAD,OPTIONS,PUT"</js>)
341    *    <jk>public class</jk> MyResource {
342    *
343    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
344    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
345    *
346    *          <jc>// Using method on builder.</jc>
347    *          builder.allowedMethodParams(<js>"HEAD,OPTIONS,PUT"</js>);
348    *
349    *          <jc>// Same, but using property.</jc>
350    *          builder.set(<jsf>REST_allowedMethodParams</jsf>, <js>"HEAD,OPTIONS,PUT"</js>);
351    *       }
352    *
353    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
354    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
355    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
356    *          builder.allowedMethodParams(<js>"HEAD,OPTIONS,PUT"</js>);
357    *       }
358    *    }
359    * </p>
360    *
361    * <ul class='notes'>
362    *    <li>
363    *       Format is a comma-delimited list of HTTP method names that can be passed in as a method parameter.
364    *    <li>
365    *       <js>'method'</js> parameter name is case-insensitive.
366    *    <li>
367    *       Use <js>"*"</js> to represent all methods.
368    *    <li>
369    *       Use <js>"NONE"</js> (case insensitive) to suppress inheriting a value from a parent class.
370    * </ul>
371    */
372   public static final String REST_allowedMethodParams = PREFIX + ".allowedMethodParams.s";
373
374   /**
375    * Configuration property:  Allow header URL parameters.
376    *
377    * <div class='warn'>
378    *    <b>Deprecated</b> - Use {@link #REST_allowedHeaderParams}
379    * </div>
380    */
381   @Deprecated
382   public static final String REST_allowHeaderParams = PREFIX + ".allowHeaderParams.b";
383
384   /**
385    * Configuration property:  REST call handler.
386    *
387    * <h5 class='section'>Property:</h5>
388    * <ul class='spaced-list'>
389    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_callHandler REST_callHandler}
390    *    <li><b>Name:</b>  <js>"RestContext.callHandler.o"</js>
391    *    <li><b>Data type:</b>
392    *       <ul>
393    *          <li>{@link org.apache.juneau.rest.RestCallHandler}
394    *          <li><c>Class&lt;{@link org.apache.juneau.rest.RestCallHandler}&gt;</c>
395    *       </ul>
396    *    <li><b>Default:</b>  {@link org.apache.juneau.rest.BasicRestCallHandler}
397    *    <li><b>Session property:</b>  <jk>false</jk>
398    *    <li><b>Annotations:</b>
399    *       <ul>
400    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#callHandler()}
401    *       </ul>
402    *    <li><b>Methods:</b>
403    *       <ul>
404    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#callHandler(Class)}
405    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#callHandler(RestCallHandler)}
406    *       </ul>
407    * </ul>
408    *
409    * <h5 class='section'>Description:</h5>
410    * <p>
411    * This class handles the basic lifecycle of an HTTP REST call.
412    * <br>Subclasses can be used to customize how these HTTP calls are handled.
413    *
414    * <h5 class='section'>Example:</h5>
415    * <p class='bcode w800'>
416    *    <jc>// Our customized call handler.</jc>
417    *    <jk>public class</jk> MyRestCallHandler <jk>extends</jk> BasicRestCallHandler {
418    *
419    *       <jc>// Must provide this constructor!</jc>
420    *       <jk>public</jk> MyRestCallHandler(RestContext context) {
421    *          <jk>super</jk>(context);
422    *       }
423    *
424    *       <ja>@Override</ja>
425    *       <jk>public</jk> RestRequest createRequest(HttpServletRequest req) <jk>throws</jk> ServletException {
426    *          <jc>// Low-level handling of requests.</jc>
427    *          ...
428    *       }
429    *
430    *       <ja>@Override</ja>
431    *       <jk>public void</jk> handleResponse(RestRequest req, RestResponse res, Object output) <jk>throws</jk> IOException, RestException {
432    *          <jc>// Low-level handling of responses.</jc>
433    *          ...
434    *       }
435    *
436    *       <ja>@Override</ja>
437    *       <jk>public void</jk> handleNotFound(int rc, RestRequest req, RestResponse res) <jk>throws</jk> Exception {
438    *          <jc>// Low-level handling of various error conditions.</jc>
439    *          ...
440    *       }
441    *    }
442    *
443    *    <jc>// Option #1 - Registered via annotation resolving to a config file setting with default value.</jc>
444    *    <ja>@Rest</ja>(callHandler=MyRestCallHandler.<jk>class</jk>)
445    *    <jk>public class</jk> MyResource {
446    *
447    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
448    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
449    *
450    *          <jc>// Using method on builder.</jc>
451    *          builder.callHandler(MyRestCallHandler.<jk>class</jk>);
452    *
453    *          <jc>// Same, but using property.</jc>
454    *          builder.set(<jsf>REST_callHandler</jsf>, MyRestCallHandler.<jk>class</jk>);
455    *       }
456    *
457    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
458    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
459    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
460    *          builder.callHandler(MyRestCallHandler.<jk>class</jk>);
461    *       }
462    *    }
463    * </p>
464    *
465    * <ul class='notes'>
466    *    <li>
467    *       When defined as a class, the implementation must have one of the following constructors:
468    *       <ul>
469    *          <li><code><jk>public</jk> T(RestContext)</code>
470    *          <li><code><jk>public</jk> T()</code>
471    *       </ul>
472    *    <li>
473    *       Inner classes of the REST resource class are allowed.
474    * </ul>
475    */
476   public static final String REST_callHandler = PREFIX + ".callHandler.o";
477
478   /**
479    * Configuration property:  REST call logger.
480    *
481    * <h5 class='section'>Property:</h5>
482    * <ul class='spaced-list'>
483    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_callLogger REST_callLogger}
484    *    <li><b>Name:</b>  <js>"RestContext.callLogger.o"</js>
485    *    <li><b>Data type:</b>
486    *       <ul>
487    *          <li>{@link org.apache.juneau.rest.RestCallLogger}
488    *          <li><c>Class&lt;{@link org.apache.juneau.rest.RestCallLogger}&gt;</c>
489    *       </ul>
490    *    <li><b>Default:</b>  {@link org.apache.juneau.rest.BasicRestCallLogger}
491    *    <li><b>Session property:</b>  <jk>false</jk>
492    *    <li><b>Annotations:</b>
493    *       <ul>
494    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#callLogger()}
495    *       </ul>
496    *    <li><b>Methods:</b>
497    *       <ul>
498    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#callLogger(Class)}
499    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#callLogger(RestCallLogger)}
500    *       </ul>
501    * </ul>
502    *
503    * <h5 class='section'>Description:</h5>
504    * <p>
505    * Specifies the logger to use for logging of HTTP requests and responses.
506    *
507    * <h5 class='section'>Example:</h5>
508    * <p class='bcode w800'>
509    *    <jc>// Our customized logger.</jc>
510    *    <jk>public class</jk> MyLogger <jk>extends</jk> BasicRestCallLogger {
511    *
512    *       <ja>@Override</ja>
513    *       <jk>public void</jk> log(RestCallLoggerConfig config, HttpServletRequest req, HttpServletResponse res) {
514    *          <jc>// Handle logging ourselves.</jc>
515    *       }
516    *    }
517    *
518    *    <jc>// Option #1 - Registered via annotation resolving to a config file setting with default value.</jc>
519    *    <ja>@Rest</ja>(callLogger=MyLogger.<jk>class</jk>)
520    *    <jk>public class</jk> MyResource {
521    *
522    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
523    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
524    *
525    *          <jc>// Using method on builder.</jc>
526    *          builder.callLogger(MyLogger.<jk>class</jk>);
527    *
528    *          <jc>// Same, but using property.</jc>
529    *          builder.set(<jsf>REST_callLogger</jsf>, MyLogger.<jk>class</jk>);
530    *       }
531    *
532    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
533    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
534    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
535    *          builder.callLogger(MyLogger.<jk>class</jk>);
536    *       }
537    *    }
538    * </p>
539    *
540    * <ul class='seealso'>
541    *    <li class='link'>{@doc juneau-rest-server.LoggingAndDebugging}
542    * </ul>
543    */
544   public static final String REST_callLogger = PREFIX + ".callLogger.o";
545
546   /**
547    * Configuration property:  REST call logging rules.
548    *
549    * <h5 class='section'>Property:</h5>
550    * <ul class='spaced-list'>
551    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_callLoggerConfig REST_callLoggerConfig}
552    *    <li><b>Name:</b>  <js>"RestContext.callLoggerConfig.o"</js>
553    *    <li><b>Data type:</b>  {@link org.apache.juneau.rest.RestCallLoggerConfig}
554    *    <li><b>Default:</b>  {@link org.apache.juneau.rest.RestCallLoggerConfig#DEFAULT}
555    *    <li><b>Session property:</b>  <jk>false</jk>
556    *    <li><b>Annotations:</b>
557    *       <ul>
558    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#logging()}
559    *       </ul>
560    *    <li><b>Methods:</b>
561    *       <ul>
562    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#callLoggerConfig(RestCallLoggerConfig)}
563    *       </ul>
564    * </ul>
565    *
566    * <h5 class='section'>Description:</h5>
567    * <p>
568    * Specifies rules on how to handle logging of HTTP requests/responses.
569    *
570    * <h5 class='section'>Example:</h5>
571    * <p class='bcode w800'>
572    *    <jc>// Option #1 - Registered via annotation.</jc>
573    *    <ja>@Rest</ja>(
574    *       logging=<ja>@Logging</ja>(
575    *          level=<js>"INFO"</js>,
576    *          rules={
577    *             <ja>@LoggingRule</ja>(codes=<js>"400-499"</js>, level=<js>"WARNING"</js>, req=<js>"SHORT"</js>, res=<js>"MEDIUM"</js>),
578    *             <ja>@LoggingRule</ja>(codes=<js>">=500"</js>, level=<js>"SEVERE"</js>, req=<js>"LONG"</js>, res=<js>"LONG"</js>)
579    *          }
580    *       }
581    *    )
582    *    <jk>public class</jk> MyResource {
583    *
584    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
585    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
586    *
587    *          <jc>// Using method on builder.</jc>
588    *          builder.callLoggerConfig(
589    *             RestCallLoggerConfig
590    *                .<jsm>create</jsm>()
591    *                .level(Level.<jsf>INFO</jsf>)
592    *                .rules(
593    *                   RestCallLoggingRule
594    *                      .<jsm>create</jsm>()
595    *                      .codes(<js>"400-499"</js>)
596    *                      .level(<jsf>WARNING</jsf>)
597    *                      .req(<jsf>SHORT</jsf>)
598    *                      .res(<jsf>MEDIUM</jsf>)
599    *                      .build(),
600    *                   RestCallLoggingRule
601    *                      .<jsm>create</jsm>()
602    *                      .codes(<js>">=500"</js>)
603    *                      .level(<jsf>SEVERE</jsf>)
604    *                      .req(<jsf>LONG</jsf>)
605    *                      .res(<jsf>LONG</jsf>)
606    *                      .build()
607    *                )
608    *                .build()
609    *          );
610    *
611    *          <jc>// Same, but using property with JSON value.</jc>
612    *          builder.set(<jsf>REST_callLoggerConfig</jsf>, <js>"{level:'INFO',rules:[{codes:'400-499',level:'WARNING',...},...]}"</js>);
613    *       }
614    *    }
615    * </p>
616    *
617    * <ul class='seealso'>
618    *    <li class='link'>{@doc juneau-rest-server.LoggingAndDebugging}
619    * </ul>
620    */
621   public static final String REST_callLoggerConfig = PREFIX + ".callLoggerConfig.o";
622
623   /**
624    * Configuration property:  Children.
625    *
626    * <h5 class='section'>Property:</h5>
627    * <ul class='spaced-list'>
628    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_children REST_children}
629    *    <li><b>Name:</b>  <js>"RestContext.children.lo"</js>
630    *    <li><b>Data type:</b>  <c>List&lt;Class|Object|{@link org.apache.juneau.rest.RestChild}&gt;</c>
631    *    <li><b>Default:</b>  empty list
632    *    <li><b>Session property:</b>  <jk>false</jk>
633    *    <li><b>Annotations:</b>
634    *       <ul>
635    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#children()}
636    *       </ul>
637    *    <li><b>Methods:</b>
638    *       <ul>
639    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#child(String,Object)}
640    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#children(Class...)}
641    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#children(Object...)}
642    *       </ul>
643    * </ul>
644    *
645    * <h5 class='section'>Description:</h5>
646    * <p>
647    * Defines children of this resource.
648    *
649    * <p>
650    * A REST child resource is simply another servlet or object that is initialized as part of the ascendant resource and has a
651    * servlet path directly under the ascendant resource object path.
652    * <br>The main advantage to defining servlets as REST children is that you do not need to define them in the
653    * <c>web.xml</c> file of the web application.
654    * <br>This can cut down on the number of entries that show up in the <c>web.xml</c> file if you are defining
655    * large numbers of servlets.
656    *
657    * <p>
658    * Child resources must specify a value for {@link Rest#path() @Rest(path)} that identifies the subpath of the child resource
659    * relative to the ascendant path UNLESS you use the {@link RestContextBuilder#child(String, Object)} method to register it.
660    *
661    * <p>
662    * Child resources can be nested arbitrarily deep using this technique (i.e. children can also have children).
663    *
664    * <dl>
665    *    <dt>Servlet initialization:</dt>
666    *    <dd>
667    *       <p>
668    *          A child resource will be initialized immediately after the ascendant servlet/resource is initialized.
669    *          <br>The child resource receives the same servlet config as the ascendant servlet/resource.
670    *          <br>This allows configuration information such as servlet initialization parameters to filter to child
671    *          resources.
672    *       </p>
673    *    </dd>
674    *    <dt>Runtime behavior:</dt>
675    *    <dd>
676    *       <p>
677    *          As a rule, methods defined on the <c>HttpServletRequest</c> object will behave as if the child
678    *          servlet were deployed as a top-level resource under the child's servlet path.
679    *          <br>For example, the <c>getServletPath()</c> and <c>getPathInfo()</c> methods on the
680    *          <c>HttpServletRequest</c> object will behave as if the child resource were deployed using the
681    *          child's servlet path.
682    *          <br>Therefore, the runtime behavior should be equivalent to deploying the child servlet in the
683    *          <c>web.xml</c> file of the web application.
684    *       </p>
685    *    </dd>
686    * </dl>
687    *
688    * <h5 class='section'>Example:</h5>
689    * <p class='bcode w800'>
690    *    <jc>// Our child resource.</jc>
691    *    <ja>@Rest</ja>(path=<js>"/child"</js>)
692    *    <jk>public class</jk> MyChildResource {...}
693    *
694    *    <jc>// Option #1 - Registered via annotation.</jc>
695    *    <ja>@Rest</ja>(children={MyChildResource.<jk>class</jk>})
696    *    <jk>public class</jk> MyResource {
697    *
698    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
699    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
700    *
701    *          <jc>// Using method on builder.</jc>
702    *          builder.children(MyChildResource.<jk>class</jk>);
703    *
704    *          <jc>// Same, but using property.</jc>
705    *          builder.addTo(<jsf>REST_children</jsf>, MyChildResource.<jk>class</jk>));
706    *
707    *          <jc>// Use a pre-instantiated object instead.</jc>
708    *          builder.child(<js>"/child"</js>, <jk>new</jk> MyChildResource());
709    *       }
710    *
711    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
712    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
713    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
714    *          builder.children(MyChildResource.<jk>class</jk>);
715    *       }
716    *    }
717    * </p>
718    *
719    * <ul class='notes'>
720    *    <li>
721    *       When defined as classes, instances are resolved using the registered {@link #REST_resourceResolver} which
722    *       by default is {@link BasicRestResourceResolver} which requires the class have one of the following
723    *       constructors:
724    *       <ul>
725    *          <li><code><jk>public</jk> T(RestContextBuilder)</code>
726    *          <li><code><jk>public</jk> T()</code>
727    *       </ul>
728    * </ul>
729    *
730    * <ul class='seealso'>
731    *    <li class='link'>{@doc juneau-rest-server.Instantiation.Children}
732    * </ul>
733    */
734   public static final String REST_children = PREFIX + ".children.lo";
735
736   /**
737    * Configuration property:  Classpath resource finder.
738    *
739    * <h5 class='section'>Property:</h5>
740    * <ul class='spaced-list'>
741    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_classpathResourceFinder REST_classpathResourceFinder}
742    *    <li><b>Name:</b>  <js>"RestContext.classpathResourceFinder.o"</js>
743    *    <li><b>Data type:</b>  {@link org.apache.juneau.utils.ClasspathResourceFinder}
744    *    <li><b>Default:</b>  {@link org.apache.juneau.utils.ClasspathResourceFinderBasic}
745    *    <li><b>Session property:</b>  <jk>false</jk>
746    *    <li><b>Annotations:</b>
747    *       <ul>
748    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#classpathResourceFinder()}
749    *       </ul>
750    *    <li><b>Methods:</b>
751    *       <ul>
752    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#classpathResourceFinder(Class)}
753    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#classpathResourceFinder(ClasspathResourceFinder)}
754    *       </ul>
755    * </ul>
756    *
757    * <h5 class='section'>Description:</h5>
758    * <p>
759    * Used to retrieve localized files from the classpath.
760    *
761    * <p>
762    * Used by the following methods:
763    * <ul class='javatree'>
764    *    <li class='jc'>{@link RestContext}
765    *    <ul>
766    *       <li class='jm'>{@link #getClasspathResource(String,Locale) getClasspathResource(String,Locale)}
767    *       <li class='jm'>{@link #getClasspathResource(Class,String,Locale) getClasspathResource(Class,String,Locale)}
768    *       <li class='jm'>{@link #getClasspathResource(Class,MediaType,String,Locale) getClasspathResource(Class,MediaType,String,Locale)}
769    *       <li class='jm'>{@link #getClasspathResource(Class,Class,MediaType,String,Locale) getClasspathResource(Class,Class,MediaType,String,Locale)}
770    *       <li class='jm'>{@link #getClasspathResourceAsString(String,Locale) getClasspathResourceAsString(String,Locale)}
771    *       <li class='jm'>{@link #getClasspathResourceAsString(Class,String,Locale) getClasspathResourceAsString(Class,String,Locale)}
772    *       <li class='jm'>{@link #resolveStaticFile(String) resolveStaticFile(String)}
773    *    </ul>
774    *    <li class='jc'>{@link RestRequest}
775    *    <ul>
776    *       <li class='jm'>{@link RestRequest#getClasspathReaderResource(String) getClasspathReaderResource(String)}
777    *       <li class='jm'>{@link RestRequest#getClasspathReaderResource(String,boolean) getClasspathReaderResource(String,boolean)}
778    *       <li class='jm'>{@link RestRequest#getClasspathReaderResource(String,boolean,MediaType,boolean) getClasspathReaderResource(String,boolean,MediaType,boolean)}
779    *    </ul>
780    * </ul>
781    *
782    * <p>
783    * It also affects the behavior of the {@link #REST_staticFiles} property.
784    *
785    * <h5 class='section'>Example:</h5>
786    * <p class='bcode w800'>
787    *    <jc>// Our customized classpath resource finder.</jc>
788    *    <jk>public class</jk> MyClasspathResourceFinder <jk>extends</jk> ClasspathResourceFinderBasic {
789    *       <ja>@Override</ja>
790    *       <jk>public</jk> InputStream findResource(Class&lt;?&gt; baseClass, String name, Locale locale) <jk>throws</jk> IOException {
791    *          <jc>// Do your own resolution.</jc>
792    *       }
793    *    }
794    *
795    *    <jc>// Option #1 - Registered via annotation.</jc>
796    *    <ja>@Rest</ja>(classpathResourceFinder=MyClasspathResourceFinder.<jk>class</jk>)
797    *    <jk>public class</jk> MyResource {
798    *
799    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
800    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
801    *
802    *          <jc>// Using method on builder.</jc>
803    *          builder.classpathResourceFinder(MyClasspathResourceFinder.<jk>class</jk>);
804    *
805    *          <jc>// Same, but using property.</jc>
806    *          builder.set(<jsf>REST_classpathResourceFinder</jsf>, MyClasspathResourceFinder.<jk>class</jk>));
807    *
808    *          <jc>// Use a pre-instantiated object instead.</jc>
809    *          builder.classpathResourceFinder(<jk>new</jk> MyClasspathResourceFinder());
810    *       }
811    *
812    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
813    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
814    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
815    *          builder.classpathResourceFinder(MyClasspathResourceFinder.<jk>class</jk>);
816    *       }
817    *    }
818    * </p>
819    *
820    * <ul class='notes'>
821    *    <li>
822    *       The default value is {@link ClasspathResourceFinderBasic} which provides basic support for finding localized
823    *       resources on the classpath and JVM working directory.
824    *       <br>The {@link ClasspathResourceFinderRecursive} is another option that also recursively searches for resources
825    *       up the class-hierarchy.
826    *       <br>Each of these classes can be extended to provide customized handling of resource retrieval.
827    *    <li>
828    *       When defined as a class, the implementation must have one of the following constructors:
829    *       <ul>
830    *          <li><code><jk>public</jk> T(RestContext)</code>
831    *          <li><code><jk>public</jk> T()</code>
832    *       </ul>
833    *    <li>
834    *       Inner classes of the REST resource class are allowed.
835    * </ul>
836    */
837   public static final String REST_classpathResourceFinder = PREFIX + ".classpathResourceFinder.o";
838
839   /**
840    * Configuration property:  Client version header.
841    *
842    * <h5 class='section'>Property:</h5>
843    * <ul class='spaced-list'>
844    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_clientVersionHeader REST_clientVersionHeader}
845    *    <li><b>Name:</b>  <js>"RestContext.clientVersionHeader.s"</js>
846    *    <li><b>Data type:</b>  <c>String</c>
847    *    <li><b>System property:</b>  <c>RestContext.clientVersionHeader</c>
848    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_CLIENTVERSIONHEADER</c>
849    *    <li><b>Default:</b>  <js>"X-Client-Version"</js>
850    *    <li><b>Session property:</b>  <jk>false</jk>
851    *    <li><b>Annotations:</b>
852    *       <ul>
853    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#clientVersionHeader()}
854    *       </ul>
855    *    <li><b>Methods:</b>
856    *       <ul>
857    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#clientVersionHeader(String)}
858    *       </ul>
859    * </ul>
860    *
861    * <h5 class='section'>Description:</h5>
862    * <p>
863    * Specifies the name of the header used to denote the client version on HTTP requests.
864    *
865    * <p>
866    * The client version is used to support backwards compatibility for breaking REST interface changes.
867    * <br>Used in conjunction with {@link RestMethod#clientVersion() @RestMethod(clientVersion)} annotation.
868    *
869    * <h5 class='section'>Example:</h5>
870    * <p class='bcode w800'>
871    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
872    *    <ja>@Rest</ja>(clientVersionHeader=<js>"$C{REST/clientVersionHeader,Client-Version}"</js>)
873    *    <jk>public class</jk> MyResource {
874    *
875    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
876    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
877    *
878    *          <jc>// Using method on builder.</jc>
879    *          builder.clientVersionHeader(<js>"Client-Version"</js>);
880    *
881    *          <jc>// Same, but using property.</jc>
882    *          builder.set(<jsf>REST_clientVersionHeader</jsf>, <js>"Client-Version"</js>);
883    *       }
884    *
885    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
886    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
887    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
888    *          builder.clientVersionHeader(<js>"Client-Version"</js>);
889    *       }
890    *    }
891    * </p>
892    * <p class='bcode w800'>
893    *    <jc>// Call this method if Client-Version is at least 2.0.
894    *    // Note that this also matches 2.0.1.</jc>
895    *    <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
896    *    <jk>public</jk> Object method1() {
897    *       ...
898    *    }
899    *
900    *    <jc>// Call this method if Client-Version is at least 1.1, but less than 2.0.</jc>
901    *    <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
902    *    <jk>public</jk> Object method2() {
903    *       ...
904    *    }
905    *
906    *    <jc>// Call this method if Client-Version is less than 1.1.</jc>
907    *    <ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
908    *    <jk>public</jk> Object method3() {
909    *       ...
910    *    }
911    * </p>
912    */
913   public static final String REST_clientVersionHeader = PREFIX + ".clientVersionHeader.s";
914
915   /**
916    * Configuration property:  Class-level response converters.
917    *
918    * <h5 class='section'>Property:</h5>
919    * <ul class='spaced-list'>
920    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_converters REST_converters}
921    *    <li><b>Name:</b>  <js>"RestContext.converters.lo"</js>
922    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.rest.RestConverter}|Class&lt;{@link org.apache.juneau.rest.RestConverter}&gt;&gt;</c>
923    *    <li><b>Default:</b>  empty list
924    *    <li><b>Session property:</b>  <jk>false</jk>
925    *    <li><b>Annotations:</b>
926    *       <ul>
927    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#converters()}
928    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#converters()}
929    *       </ul>
930    *    <li><b>Methods:</b>
931    *       <ul>
932    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#converters(Class...)}
933    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#converters(RestConverter...)}
934    *       </ul>
935    * </ul>
936    *
937    * <h5 class='section'>Description:</h5>
938    * <p>
939    * Associates one or more {@link RestConverter converters} with a resource class.
940    * <br>These converters get called immediately after execution of the REST method in the same order specified in the
941    * annotation.
942    * <br>The object passed into this converter is the object returned from the Java method or passed into
943    * the {@link RestResponse#setOutput(Object)} method.
944    *
945    * <p>
946    * Can be used for performing post-processing on the response object before serialization.
947    *
948    * <p>
949    *    When multiple converters are specified, they're executed in the order they're specified in the annotation
950    *    (e.g. first the results will be traversed, then the resulting node will be searched/sorted).
951    *
952    * <h5 class='section'>Example:</h5>
953    * <p class='bcode w800'>
954    *    <jc>// Our converter.</jc>
955    *    <jk>public class</jk> MyConverter <jk>implements</jk> RestConverter {
956    *       <ja>@Override</ja>
957    *       <jk>public</jk> Object convert(RestRequest req, Object o) {
958    *          <jc>// Do something with object and return another object.</jc>
959    *          <jc>// Or just return the same object for a no-op.</jc>
960    *       }
961    *    }
962    *
963    *    <jc>// Option #1 - Registered via annotation resolving to a config file setting with default value.</jc>
964    *    <ja>@Rest</ja>(converters={MyConverter.<jk>class</jk>})
965    *    <jk>public class</jk> MyResource {
966    *
967    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
968    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
969    *
970    *          <jc>// Using method on builder.</jc>
971    *          builder.converters(MyConverter.<jk>class</jk>);
972    *
973    *          <jc>// Same, but using property.</jc>
974    *          builder.set(<jsf>REST_converters</jsf>, MyConverter.<jk>class</jk>);
975    *
976    *          <jc>// Pass in an instance instead.</jc>
977    *          builder.converters(<jk>new</jk> MyConverter());
978    *       }
979    *
980    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
981    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
982    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
983    *          builder.converters(MyConverter.<jk>class</jk>);
984    *       }
985    *    }
986    * </p>
987    *
988    * <ul class='seealso'>
989    *    <li class='jc'>{@link Traversable} - Allows URL additional path info to address individual elements in a POJO tree.
990    *    <li class='jc'>{@link Queryable} - Allows query/view/sort functions to be performed on POJOs.
991    *    <li class='jc'>{@link Introspectable} - Allows Java public methods to be invoked on the returned POJOs.
992    *    <li class='link'>{@doc juneau-rest-server.Converters}
993    * </ul>
994    *
995    * <ul class='notes'>
996    *    <li>
997    *       When defined as a class, the implementation must have one of the following constructors:
998    *       <ul>
999    *          <li><code><jk>public</jk> T(BeanContext)</code>
1000    *          <li><code><jk>public</jk> T()</code>
1001    *       </ul>
1002    *    <li>
1003    *       Inner classes of the REST resource class are allowed.
1004    * </ul>
1005    */
1006   public static final String REST_converters = PREFIX + ".converters.lo";
1007
1008   /**
1009    * Configuration property:  Debug mode.
1010    *
1011    * <h5 class='section'>Property:</h5>
1012    * <ul class='spaced-list'>
1013    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_debug REST_debug}
1014    *    <li><b>Name:</b>  <js>"RestContext.debug.s"</js>
1015    *    <li><b>Data type:</b>  {@link org.apache.juneau.rest.Enablement}
1016    *    <li><b>System property:</b>  <c>RestContext.debug</c>
1017    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_DEBUG</c>
1018    *    <li><b>Default:</b>  {@link org.apache.juneau.rest.Enablement#FALSE}
1019    *    <li><b>Session property:</b>  <jk>false</jk>
1020    *    <li><b>Annotations:</b>
1021    *       <ul>
1022    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#debug()}
1023    *       </ul>
1024    *    <li><b>Methods:</b>
1025    *       <ul>
1026    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#debug(boolean)}
1027    *       </ul>
1028    * </ul>
1029    *
1030    * <h5 class='section'>Description:</h5>
1031    * <p>
1032    * Enables the following:
1033    * <ul class='spaced-list'>
1034    *    <li>
1035    *       HTTP request/response bodies are cached in memory for logging purposes.
1036    * </ul>
1037    */
1038   public static final String REST_debug = PREFIX + ".debug.s";
1039
1040   /**
1041    * Configuration property:  Default character encoding.
1042    *
1043    * <h5 class='section'>Property:</h5>
1044    * <ul class='spaced-list'>
1045    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_defaultCharset REST_defaultCharset}
1046    *    <li><b>Name:</b>  <js>"RestContext.defaultCharset.s"</js>
1047    *    <li><b>Data type:</b>  <c>String</c>
1048    *    <li><b>System property:</b>  <c>RestContext.defaultCharset</c>
1049    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_DEFAULTCHARSET</c>
1050    *    <li><b>Default:</b>  <js>"utf-8"</js>
1051    *    <li><b>Session property:</b>  <jk>false</jk>
1052    *    <li><b>Annotations:</b>
1053    *       <ul>
1054    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#defaultCharset()}
1055    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#defaultCharset()}
1056    *       </ul>
1057    *    <li><b>Methods:</b>
1058    *       <ul>
1059    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#defaultCharset(String)}
1060    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#defaultCharset(Charset)}
1061    *       </ul>
1062    * </ul>
1063    *
1064    * <h5 class='section'>Description:</h5>
1065    * <p>
1066    * The default character encoding for the request and response if not specified on the request.
1067    *
1068    * <h5 class='section'>Example:</h5>
1069    * <p class='bcode w800'>
1070    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
1071    *    <ja>@Rest</ja>(defaultCharset=<js>"$C{REST/defaultCharset,US-ASCII}"</js>)
1072    *    <jk>public class</jk> MyResource {
1073    *
1074    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1075    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1076    *
1077    *          <jc>// Using method on builder.</jc>
1078    *          builder.defaultCharset(<js>"US-ASCII"</js>);
1079    *
1080    *          <jc>// Same, but using property.</jc>
1081    *          builder.set(<jsf>REST_defaultCharset</jsf>, <js>"US-ASCII"</js>);
1082    *       }
1083    *
1084    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1085    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1086    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1087    *          builder.defaultCharset(<js>"US-ASCII"</js>);
1088    *       }
1089    *
1090    *       <jc>// Override at the method level.</jc>
1091    *       <ja>@RestMethod</ja>(defaultCharset=<js>"UTF-16"</js>)
1092    *       public Object myMethod() {...}
1093    *    }
1094    * </p>
1095    */
1096   public static final String REST_defaultCharset = PREFIX + ".defaultCharset.s";
1097
1098   /**
1099    * Configuration property:  Default request attributes.
1100    *
1101    * <div class='warn'>
1102    *    <b>Deprecated</b> - Use {@link #REST_reqAttrs}
1103    * </div>
1104    */
1105   @Deprecated
1106   public static final String REST_attrs = PREFIX + ".reqAttrs.smo";
1107
1108   /**
1109    * Configuration property:  Default request headers.
1110    *
1111    * <div class='warn'>
1112    *    <b>Deprecated</b> - Use {@link #REST_reqHeaders}
1113    * </div>
1114    */
1115   @Deprecated
1116   public static final String REST_defaultRequestHeaders = PREFIX + ".reqHeaders.smo";
1117
1118   /**
1119    * Configuration property:  Default response headers.
1120    *
1121    * <div class='warn'>
1122    *    <b>Deprecated</b> - Use {@link #REST_resHeaders}
1123    * </div>
1124    */
1125   @Deprecated
1126   public static final String REST_defaultResponseHeaders = PREFIX + ".resHeaders.omo";
1127
1128   /**
1129    * Configuration property:  Compression encoders.
1130    *
1131    * <h5 class='section'>Property:</h5>
1132    * <ul class='spaced-list'>
1133    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_encoders REST_encoders}
1134    *    <li><b>Name:</b>  <js>"RestContext.encoders.o"</js>
1135    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.encoders.Encoder}|Class&lt;{@link org.apache.juneau.encoders.Encoder}&gt;&gt;</c>
1136    *    <li><b>Default:</b>  empty list
1137    *    <li><b>Session property:</b>  <jk>false</jk>
1138    *    <li><b>Annotations:</b>
1139    *       <ul>
1140    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#encoders()}
1141    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#encoders()}
1142    *       </ul>
1143    *    <li><b>Methods:</b>
1144    *       <ul>
1145    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#encoders(Class...)}
1146    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#encoders(Encoder...)}
1147    *       </ul>
1148    * </ul>
1149    *
1150    * <h5 class='section'>Description:</h5>
1151    * <p>
1152    * These can be used to enable various kinds of compression (e.g. <js>"gzip"</js>) on requests and responses.
1153    *
1154    * <h5 class='section'>Example:</h5>
1155    * <p class='bcode w800'>
1156    *    <jc>// Option #1 - Registered via annotation.</jc>
1157    *    <ja>@Rest</ja>(encoders={GzipEncoder.<jk>class</jk>})
1158    *    <jk>public class</jk> MyResource {
1159    *
1160    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
1161    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1162    *
1163    *          <jc>// Using method on builder.</jc>
1164    *          builder.encoders(GzipEncoder.<jk>class</jk>);
1165    *
1166    *          <jc>// Same, but using property.</jc>
1167    *          builder.addTo(<jsf>REST_encoders</jsf>, GzipEncoder.<jk>class</jk>);
1168    *       }
1169    *
1170    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
1171    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1172    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1173    *          builder.encoders(GzipEncoder.<jk>class</jk>);
1174    *       }
1175    *
1176    *       <jc>// Override at the method level.</jc>
1177    *       <ja>@RestMethod</ja>(encoders={MySpecialEncoder.<jk>class</jk>}, inherit={<js>"ENCODERS"</js>})
1178    *       public Object myMethod() {...}
1179    *    }
1180    * </p>
1181    *
1182    * <ul class='notes'>
1183    *    <li>
1184    *       When defined as a class, the implementation must have one of the following constructors:
1185    *       <ul>
1186    *          <li><code><jk>public</jk> T(BeanContext)</code>
1187    *          <li><code><jk>public</jk> T()</code>
1188    *       </ul>
1189    *    <li>
1190    *       Inner classes of the REST resource class are allowed.
1191    * </ul>
1192    *
1193    * <ul class='seealso'>
1194    *    <li class='link'>{@doc juneau-rest-server.Encoders}
1195    * </ul>
1196    */
1197   public static final String REST_encoders = PREFIX + ".encoders.lo";
1198
1199   /**
1200    * Configuration property:  Class-level guards.
1201    *
1202    * <h5 class='section'>Property:</h5>
1203    * <ul class='spaced-list'>
1204    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_guards REST_guards}
1205    *    <li><b>Name:</b>  <js>"RestContext.guards.lo"</js>
1206    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.rest.RestGuard}|Class&lt;{@link org.apache.juneau.rest.RestGuard}&gt;&gt;</c>
1207    *    <li><b>Default:</b>  empty list
1208    *    <li><b>Session property:</b>  <jk>false</jk>
1209    *    <li><b>Annotations:</b>
1210    *       <ul>
1211    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#guards()}
1212    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#guards()}
1213    *       </ul>
1214    *    <li><b>Methods:</b>
1215    *       <ul>
1216    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#guards(Class...)}
1217    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#guards(RestGuard...)}
1218    *       </ul>
1219    * </ul>
1220    *
1221    * <h5 class='section'>Description:</h5>
1222    * <p>
1223    * Associates one or more {@link RestGuard RestGuards} with all REST methods defined in this class.
1224    * <br>These guards get called immediately before execution of any REST method in this class.
1225    *
1226    * <p>
1227    * If multiple guards are specified, <b>ALL</b> guards must pass.
1228    * <br>Note that this is different than matchers where only ONE matcher needs to pass.
1229    *
1230    * <h5 class='section'>Example:</h5>
1231    * <p class='bcode w800'>
1232    *    <jc>// Define a guard that only lets Billy make a request.</jc>
1233    *    <jk>public</jk> BillyGuard <jk>extends</jk> RestGuard {
1234    *       <ja>@Override</ja>
1235    *       <jk>public boolean</jk> isRequestAllowed(RestRequest req) {
1236    *          <jk>return</jk> req.getUserPrincipal().getName().equals(<js>"Billy"</js>);
1237    *       }
1238    *    }
1239    *
1240    *    <jc>// Option #1 - Registered via annotation.</jc>
1241    *    <ja>@Rest</ja>(guards={BillyGuard.<jk>class</jk>})
1242    *    <jk>public class</jk> MyResource {
1243    *
1244    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
1245    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1246    *
1247    *          <jc>// Using method on builder.</jc>
1248    *          builder.guards(BillyGuard.<jk>class</jk>);
1249    *
1250    *          <jc>// Same, but using property.</jc>
1251    *          builder.addTo(<jsf>REST_guards</jsf>, BillyGuard.<jk>class</jk>);
1252    *       }
1253    *
1254    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
1255    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1256    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1257    *          builder.guards(BillyGuard.<jk>class</jk>);
1258    *       }
1259    *
1260    *       <jc>// Override at the method level.</jc>
1261    *       <ja>@RestMethod</ja>(guards={SomeOtherGuard.<jk>class</jk>})
1262    *       public Object myMethod() {...}
1263    *    }
1264    * </p>
1265    *
1266    * <ul class='notes'>
1267    *    <li>
1268    *       When defined as a class, the implementation must have one of the following constructors:
1269    *       <ul>
1270    *          <li><code><jk>public</jk> T(RestContext)</code>
1271    *          <li><code><jk>public</jk> T()</code>
1272    *       </ul>
1273    *    <li>
1274    *       Inner classes of the REST resource class are allowed.
1275    * </ul>
1276    *
1277    * <ul class='seealso'>
1278    *    <li class='link'>{@doc juneau-rest-server.Guards}
1279    * </ul>
1280    */
1281   public static final String REST_guards = PREFIX + ".guards.lo";
1282
1283   /**
1284    * Configuration property:  REST info provider.
1285    *
1286    * <h5 class='section'>Property:</h5>
1287    * <ul class='spaced-list'>
1288    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_infoProvider REST_infoProvider}
1289    *    <li><b>Name:</b>  <js>"RestContext.infoProvider.o"</js>
1290    *    <li><b>Data type:</b>
1291    *       <ul>
1292    *          <li>{@link org.apache.juneau.rest.RestInfoProvider}
1293    *          <li><c>Class&lt;{@link org.apache.juneau.rest.RestInfoProvider}&gt;</c>
1294    *       </ul>
1295    *    <li><b>Default:</b>  {@link org.apache.juneau.rest.BasicRestInfoProvider}
1296    *    <li><b>Session property:</b>  <jk>false</jk>
1297    *    <li><b>Annotations:</b>
1298    *       <ul>
1299    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#infoProvider()}
1300    *       </ul>
1301    *    <li><b>Methods:</b>
1302    *       <ul>
1303    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#infoProvider(Class)}
1304    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#infoProvider(RestInfoProvider)}
1305    *       </ul>
1306    * </ul>
1307    *
1308    * <h5 class='section'>Description:</h5>
1309    * <p>
1310    * Class used to retrieve title/description/swagger information about a resource.
1311    *
1312    * <h5 class='section'>Example:</h5>
1313    * <p class='bcode w800'>
1314    *    <jc>// Our customized info provider.</jc>
1315    *    <jc>// Extend from the default implementation and selectively override values.</jc>
1316    *    <jk>public class</jk> MyRestInfoProvider <jk>extends</jk> BasicRestInfoProvider {
1317    *
1318    *       <jc>// Must provide this constructor!</jc>
1319    *       <jk>public</jk> MyRestInfoProvider(RestContext context) {
1320    *          <jk>super</jk>(context);
1321    *       }
1322    *
1323    *       <ja>@Override</ja>
1324    *       <jk>public</jk> Swagger getSwaggerFromFile(RestRequest req) <jk>throws</jk> RestException {
1325    *          <jc>// Provide our own method of retrieving swagger from file system.</jc>
1326    *       }
1327    *
1328    *       <ja>@Override</ja>
1329    *       <jk>public</jk> Swagger getSwagger(RestRequest req) <jk>throws</jk> RestException {
1330    *          Swagger s = <jk>super</jk>.getSwagger(req);
1331    *          <jc>// Made inline modifications to generated swagger.</jc>
1332    *          <jk>return</jk> s;
1333    *       }
1334    *
1335    *       <ja>@Override</ja>
1336    *       <jk>public</jk> String getSiteName(RestRequest req) {
1337    *          <jc>// Override the site name.</jc>
1338    *       }
1339    *    }
1340    *
1341    *    <jc>// Option #1 - Registered via annotation resolving to a config file setting with default value.</jc>
1342    *    <ja>@Rest</ja>(infoProvider=MyRestInfoProvider.<jk>class</jk>)
1343    *    <jk>public class</jk> MyResource {
1344    *
1345    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
1346    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1347    *
1348    *          <jc>// Using method on builder.</jc>
1349    *          builder.infoProvider(MyRestInfoProvider.<jk>class</jk>);
1350    *
1351    *          <jc>// Same, but using property.</jc>
1352    *          builder.set(<jsf>REST_infoProvider</jsf>, MyRestInfoProvider.<jk>class</jk>);
1353    *       }
1354    *
1355    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
1356    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1357    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1358    *          builder.infoProvider(MyRestInfoProvider.<jk>class</jk>);
1359    *       }
1360    *    }
1361    * </p>
1362    *
1363    * <ul class='notes'>
1364    *    <li>
1365    *       When defined as a class, the implementation must have one of the following constructors:
1366    *       <ul>
1367    *          <li><code><jk>public</jk> T(RestContext)</code>
1368    *          <li><code><jk>public</jk> T()</code>
1369    *       </ul>
1370    *    <li>
1371    *       Inner classes of the REST resource class are allowed.
1372    * </ul>
1373    */
1374   public static final String REST_infoProvider = PREFIX + ".infoProvider.o";
1375
1376   /**
1377    * Configuration property:  REST logger.
1378    *
1379    * <div class='warn'>
1380    *    <b>Deprecated</b> - Use {@link #REST_callLogger}
1381    * </div>
1382    */
1383   @Deprecated
1384   public static final String REST_logger = PREFIX + ".logger.o";
1385
1386   /**
1387    * Configuration property:  The maximum allowed input size (in bytes) on HTTP requests.
1388    *
1389    * <h5 class='section'>Property:</h5>
1390    * <ul class='spaced-list'>
1391    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_maxInput REST_maxInput}
1392    *    <li><b>Name:</b>  <js>"RestContext.maxInput.s"</js>
1393    *    <li><b>Data type:</b>  <c>String</c>
1394    *    <li><b>System property:</b>  <c>RestContext.maxInput</c>
1395    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_MAXINPUT</c>
1396    *    <li><b>Default:</b>  <js>"100M"</js>
1397    *    <li><b>Session property:</b>  <jk>false</jk>
1398    *    <li><b>Annotations:</b>
1399    *       <ul>
1400    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#maxInput()}
1401    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#maxInput()}
1402    *       </ul>
1403    *    <li><b>Methods:</b>
1404    *       <ul>
1405    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#maxInput(String)}
1406    *       </ul>
1407    * </ul>
1408    *
1409    * <h5 class='section'>Description:</h5>
1410    * <p>
1411    * Useful for alleviating DoS attacks by throwing an exception when too much input is received instead of resulting
1412    * in out-of-memory errors which could affect system stability.
1413    *
1414    * <h5 class='section'>Example:</h5>
1415    * <p class='bcode w800'>
1416    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
1417    *    <ja>@Rest</ja>(maxInput=<js>"$C{REST/maxInput,10M}"</js>)
1418    *    <jk>public class</jk> MyResource {
1419    *
1420    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1421    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1422    *
1423    *          <jc>// Using method on builder.</jc>
1424    *          builder.maxInput(<js>"10M"</js>);
1425    *
1426    *          <jc>// Same, but using property.</jc>
1427    *          builder.set(<jsf>REST_maxInput</jsf>, <js>"10M"</js>);
1428    *       }
1429    *
1430    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1431    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1432    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1433    *          builder.maxInput(<js>"10M"</js>);
1434    *       }
1435    *
1436    *       <jc>// Override at the method level.</jc>
1437    *       <ja>@RestMethod</ja>(maxInput=<js>"10M"</js>)
1438    *       public Object myMethod() {...}
1439    *    }
1440    * </p>
1441    *
1442    * <ul class='notes'>
1443    *    <li>
1444    *       String value that gets resolved to a <jk>long</jk>.
1445    *    <li>
1446    *       Can be suffixed with any of the following representing kilobytes, megabytes, and gigabytes:
1447    *       <js>'K'</js>, <js>'M'</js>, <js>'G'</js>.
1448    *    <li>
1449    *       A value of <js>"-1"</js> can be used to represent no limit.
1450    * </ul>
1451    */
1452   public static final String REST_maxInput = PREFIX + ".maxInput.s";
1453
1454   /**
1455    * Configuration property:  Messages.
1456    *
1457    * <h5 class='section'>Property:</h5>
1458    * <ul class='spaced-list'>
1459    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_messages REST_messages}
1460    *    <li><b>Name:</b>  <js>"RestContext.messages.lo"</js>
1461    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.rest.MessageBundleLocation}&gt;</c>
1462    *    <li><b>Default:</b>  <jk>null</jk>
1463    *    <li><b>Session property:</b>  <jk>false</jk>
1464    *    <li><b>Annotations:</b>
1465    *       <ul>
1466    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#messages()}
1467    *       </ul>
1468    *    <li><b>Methods:</b>
1469    *       <ul>
1470    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#messages(String)},
1471    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#messages(Class,String)}
1472    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#messages(MessageBundleLocation...)}
1473    *       </ul>
1474    * </ul>
1475    *
1476    * <h5 class='section'>Description:</h5>
1477    * <p>
1478    * Identifies the location of the resource bundle for this class.
1479    *
1480    * <p>
1481    * This annotation is used to provide localized messages for the following methods:
1482    * <ul class='javatree'>
1483    *    <li class='jm'>{@link RestRequest#getMessage(String, Object...)}
1484    *    <li class='jm'>{@link RestContext#getMessages() RestContext.getMessages()}
1485    * </ul>
1486    *
1487    * <p>
1488    * Messages are also available by passing either of the following parameter types into your Java method:
1489    * <ul class='javatree'>
1490    *    <li class='jc'>{@link ResourceBundle} - Basic Java resource bundle.
1491    *    <li class='jc'>{@link MessageBundle} - Extended resource bundle with several convenience methods.
1492    * </ul>
1493    *
1494    * <p>
1495    * Messages passed into Java methods already have their locale set to that of the incoming request.
1496    *
1497    * <p>
1498    * The value can be a relative path like <js>"nls/Messages"</js>, indicating to look for the resource bundle
1499    * <js>"com.foo.sample.nls.Messages"</js> if the resource class is in <js>"com.foo.sample"</js>, or it can be an
1500    * absolute path like <js>"com.foo.sample.nls.Messages"</js>
1501    *
1502    * <h5 class='section'>Examples:</h5>
1503    * <p class='bcode w800'>
1504    *    <jk>package</jk> org.apache.foo;
1505    *
1506    *    <jc>// Resolve messages to org/apache/foo/nls/MyMessages.properties</jc>
1507    *    <ja>@Rest</ja>(messages=<js>"nls/MyMessages"</js>)
1508    *    <jk>public class</jk> MyResource {...}
1509    *
1510    *       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/hello/{you}"</js>)
1511    *       <jk>public</jk> Object helloYou(RestRequest req, MessageBundle messages, <ja>@Path</ja>(<js>"name"</js>) String you)) {
1512    *          String s;
1513    *
1514    *          <jc>// Get it from the RestRequest object.</jc>
1515    *          s = req.getMessage(<js>"HelloMessage"</js>, you);
1516    *
1517    *          <jc>// Or get it from the method parameter.</jc>
1518    *          s = messages.getString(<js>"HelloMessage"</js>, you);
1519    *
1520    *          <jc>// Or get the message in a locale different from the request.</jc>
1521    *          s = messages.getString(Locale.<jsf>UK</jsf>, <js>"HelloMessage"</js>, you);
1522    *
1523    *          <jk>return</jk> s;
1524    *       }
1525    *    }
1526    * </p>
1527    *
1528    * <ul class='notes'>
1529    *    <li
1530    *       >Mappings are cumulative from super classes.
1531    *       <br>Therefore, you can find and retrieve messages up the class-hierarchy chain.
1532    * </ul>
1533    *
1534    * <ul class='seealso'>
1535    *    <li class='link'>{@doc juneau-rest-server.Messages}
1536    * </ul>
1537    */
1538   public static final String REST_messages = PREFIX + ".messages.lo";
1539
1540   /**
1541    * Configuration property:  MIME types.
1542    *
1543    * <h5 class='section'>Property:</h5>
1544    * <ul class='spaced-list'>
1545    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_mimeTypes REST_mimeTypes}
1546    *    <li><b>Name:</b>  <js>"RestContext.mimeTypes.ss"</js>
1547    *    <li><b>Data type:</b>  <c>Set&lt;String&gt;</c>
1548    *    <li><b>System property:</b>  <c>RestContext.mimeTypes</c>
1549    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_MIMETYPES</c>
1550    *    <li><b>Default:</b>  empty list
1551    *    <li><b>Session property:</b>  <jk>false</jk>
1552    *    <li><b>Annotations:</b>
1553    *       <ul>
1554    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#mimeTypes()}
1555    *       </ul>
1556    *    <li><b>Methods:</b>
1557    *       <ul>
1558    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#mimeTypes(String...)}
1559    *       </ul>
1560    * </ul>
1561    *
1562    * <h5 class='section'>Description:</h5>
1563    * <p>
1564    * Defines MIME-type file type mappings.
1565    *
1566    * <p>
1567    * Used for specifying the content type on file resources retrieved through the following methods:
1568    * <ul class='javatree'>
1569    *    <li class='jm'>{@link RestContext#resolveStaticFile(String) RestContext.resolveStaticFile(String)}
1570    *    <li class='jm'>{@link RestRequest#getClasspathReaderResource(String,boolean,MediaType,boolean)}
1571    *    <li class='jm'>{@link RestRequest#getClasspathReaderResource(String,boolean)}
1572    *    <li class='jm'>{@link RestRequest#getClasspathReaderResource(String)}
1573    * </ul>
1574    *
1575    * <p>
1576    * This list appends to the existing list provided by {@link ExtendedMimetypesFileTypeMap}.
1577    *
1578    * <h5 class='section'>Example:</h5>
1579    * <p class='bcode w800'>
1580    *    <jc>// Option #1 - Defined via annotation.</jc>
1581    *    <ja>@Rest</ja>(mimeTypes={<js>"text/plain txt text TXT"</js>})
1582    *    <jk>public class</jk> MyResource {
1583    *
1584    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1585    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1586    *
1587    *          <jc>// Using method on builder.</jc>
1588    *          builder.mimeTypes(<js>"text/plain txt text TXT"</js>);
1589    *
1590    *          <jc>// Same, but using property.</jc>
1591    *          builder.addTo(<jsf>REST_mimeTypes</jsf>, <js>"text/plain txt text TXT"</js>);
1592    *       }
1593    *
1594    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1595    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1596    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1597    *          builder.mimeTypes(<js>"text/plain txt text TXT"</js>);
1598    *       }
1599    *    }
1600    * </p>
1601    *
1602    * <ul class='notes'>
1603    *    <li>
1604    *       Values are .mime.types formatted entry string.
1605    *       <br>Example: <js>"image/svg+xml svg"</js>
1606    * </ul>
1607    */
1608   public static final String REST_mimeTypes = PREFIX + ".mimeTypes.ss";
1609
1610   /**
1611    * Configuration property:  Java method parameter resolvers.
1612    *
1613    * <h5 class='section'>Property:</h5>
1614    * <ul class='spaced-list'>
1615    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_paramResolvers REST_paramResolvers}
1616    *    <li><b>Name:</b>  <js>"RestContext.paramResolvers.lo"</js>
1617    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.rest.RestMethodParam}|Class&lt;{@link org.apache.juneau.rest.RestMethodParam}&gt;&gt;</c>
1618    *    <li><b>Default:</b>  empty list
1619    *    <li><b>Session property:</b>  <jk>false</jk>
1620    *    <li><b>Annotations:</b>
1621    *       <ul>
1622    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#paramResolvers()}
1623    *       </ul>
1624    *    <li><b>Methods:</b>
1625    *       <ul>
1626    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#paramResolvers(Class...)}
1627    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#paramResolvers(RestMethodParam...)}
1628    *       </ul>
1629    * </ul>
1630    *
1631    * <h5 class='section'>Description:</h5>
1632    * <p>
1633    * By default, the Juneau framework will automatically Java method parameters of various types (e.g.
1634    * <c>RestRequest</c>, <c>Accept</c>, <c>Reader</c>).
1635    * This setting allows you to provide your own resolvers for your own class types that you want resolved.
1636    *
1637    * <p>
1638    * For example, if you want to pass in instances of <c>MySpecialObject</c> to your Java method, define
1639    * the following resolver:
1640    * <p class='bcode w800'>
1641    *    <jc>// Define a parameter resolver for resolving MySpecialObject objects.</jc>
1642    *    <jk>public class</jk> MyRestParam <jk>extends</jk> RestMethodParam {
1643    *
1644    *       <jc>// Must have no-arg constructor!</jc>
1645    *       <jk>public</jk> MyRestParam() {
1646    *          <jc>// First two parameters help with Swagger doc generation.</jc>
1647    *          <jk>super</jk>(<jsf>QUERY</jsf>, <js>"myparam"</js>, MySpecialObject.<jk>class</jk>);
1648    *       }
1649    *
1650    *       <jc>// The method that creates our object.
1651    *       // In this case, we're taking in a query parameter and converting it to our object.</jc>
1652    *       <jk>public</jk> Object resolve(RestRequest req, RestResponse res) <jk>throws</jk> Exception {
1653    *          <jk>return new</jk> MySpecialObject(req.getQuery().get(<js>"myparam"</js>));
1654    *       }
1655    *    }
1656    *
1657    *    <jc>// Option #1 - Registered via annotation.</jc>
1658    *    <ja>@Rest</ja>(paramResolvers=MyRestParam.<jk>class</jk>)
1659    *    <jk>public class</jk> MyResource {
1660    *
1661    *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
1662    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1663    *
1664    *          <jc>// Using method on builder.</jc>
1665    *          builder.paramResolvers(MyRestParam.<jk>class</jk>);
1666    *
1667    *          <jc>// Same, but using property.</jc>
1668    *          builder.addTo(<jsf>REST_paramResolver</jsf>, MyRestParam.<jk>class</jk>);
1669    *       }
1670    *
1671    *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
1672    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1673    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1674    *          builder.paramResolvers(MyRestParam.<jk>class</jk>);
1675    *       }
1676    *
1677    *       <jc>// Now pass it into your method.</jc>
1678    *       <ja>@RestMethod</ja>(...)
1679    *       <jk>public</jk> Object doMyMethod(MySpecialObject mySpeciaObject) {
1680    *          <jc>// Do something with it.</jc>
1681    *       }
1682    *    }
1683    * </p>
1684    *
1685    * <ul class='notes'>
1686    *    <li>
1687    *       When defined as a class, the implementation must have one of the following constructors:
1688    *       <ul>
1689    *          <li><code><jk>public</jk> T(BeanContext)</code>
1690    *          <li><code><jk>public</jk> T()</code>
1691    *       </ul>
1692    *    <li>
1693    *       Inner classes of the REST resource class are allowed.
1694    *    <li>
1695    *       Refer to {@link RestMethodParam} for the list of predefined parameter resolvers.
1696    * </ul>
1697    */
1698   public static final String REST_paramResolvers = PREFIX + ".paramResolvers.lo";
1699
1700   /**
1701    * Configuration property:  Parsers.
1702    *
1703    * <h5 class='section'>Property:</h5>
1704    * <ul class='spaced-list'>
1705    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_parsers REST_parsers}
1706    *    <li><b>Name:</b>  <js>"RestContext.parsers.lo"</js>
1707    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.parser.Parser}|Class&lt;{@link org.apache.juneau.parser.Parser}&gt;&gt;</c>
1708    *    <li><b>Default:</b>  empty list
1709    *    <li><b>Session property:</b>  <jk>false</jk>
1710    *    <li><b>Annotations:</b>
1711    *       <ul>
1712    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#parsers()}
1713    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#parsers()}
1714    *       </ul>
1715    *    <li><b>Methods:</b>
1716    *       <ul>
1717    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#parsers(Object...)}
1718    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#parsers(Class...)}
1719    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#parsersReplace(Object...)}
1720    *       </ul>
1721    * </ul>
1722    *
1723    * <h5 class='section'>Description:</h5>
1724    * <p>
1725    * Adds class-level parsers to this resource.
1726    *
1727    * <p>
1728    * Parsers are used to convert the body of HTTP requests into POJOs.
1729    * <br>Any of the Juneau framework parsers can be used in this setting.
1730    * <br>The parser selected is based on the request <c>Content-Type</c> header matched against the values returned by the following method
1731    * using a best-match algorithm:
1732    * <ul class='javatree'>
1733    *    <li class='jm'>{@link Parser#getMediaTypes()}
1734    * </ul>
1735    *
1736    * <h5 class='section'>Example:</h5>
1737    * <p class='bcode w800'>
1738    *    <jc>// Option #1 - Defined via annotation.</jc>
1739    *    <ja>@Rest</ja>(parsers={JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>})
1740    *    <jk>public class</jk> MyResource {
1741    *
1742    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1743    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1744    *
1745    *          <jc>// Using method on builder.</jc>
1746    *          builder.parsers(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
1747    *
1748    *          <jc>// Same, but use pre-instantiated parsers.</jc>
1749    *          builder.parsers(JsonParser.<jsf>DEFAULT</jsf>, XmlParser.<jsf>DEFAULT</jsf>);
1750    *
1751    *          <jc>// Same, but using property.</jc>
1752    *          builder.set(<jsf>REST_parsers</jsf>, JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
1753    *       }
1754    *
1755    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1756    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1757    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1758    *          builder.parsers(JsonParser.<jk>class</jk>, XmlParser.<jk>class</jk>);
1759    *       }
1760    *
1761    *       <jc>// Override at the method level.</jc>
1762    *       <ja>@RestMethod</ja>(parsers={HtmlParser.<jk>class</jk>})
1763    *       <jk>public</jk> Object myMethod(<ja>@Body</ja> MyPojo myPojo) {
1764    *          <jc>// Do something with your parsed POJO.</jc>
1765    *       }
1766    *    }
1767    * </p>
1768    *
1769    * <ul class='notes'>
1770    *    <li>
1771    *       When defined as a class, properties/transforms defined on the resource/method are inherited.
1772    *    <li>
1773    *       When defined as an instance, properties/transforms defined on the resource/method are NOT inherited.
1774    *    <li>
1775    *       Typically, you'll want your resource to extend directly from {@link BasicRestServlet} which comes
1776    *       preconfigured with the following parsers:
1777    *       <ul>
1778    *          <li class='jc'>{@link JsonParser}
1779    *          <li class='jc'>{@link XmlParser}
1780    *          <li class='jc'>{@link HtmlParser}
1781    *          <li class='jc'>{@link UonParser}
1782    *          <li class='jc'>{@link UrlEncodingParser}
1783    *          <li class='jc'>{@link MsgPackParser}
1784    *          <li class='jc'>{@link PlainTextParser}
1785    *       </ul>
1786    * </ul>
1787    *
1788    * <ul class='seealso'>
1789    *    <li class='link'>{@doc juneau-rest-server.Parsers}
1790    * </ul>
1791    */
1792   public static final String REST_parsers = PREFIX + ".parsers.lo";
1793
1794   /**
1795    * Configuration property:  HTTP part parser.
1796    *
1797    * <h5 class='section'>Property:</h5>
1798    * <ul class='spaced-list'>
1799    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_partParser REST_partParser}
1800    *    <li><b>Name:</b>  <js>"RestContext.partParser.o"</js>
1801    *    <li><b>Data type:</b>  <c>{@link org.apache.juneau.httppart.HttpPartParser}|Class&lt;{@link org.apache.juneau.httppart.HttpPartParser}&gt;</c>
1802    *    <li><b>Default:</b>  {@link org.apache.juneau.oapi.OpenApiParser}
1803    *    <li><b>Session property:</b>  <jk>false</jk>
1804    *    <li><b>Annotations:</b>
1805    *       <ul>
1806    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#partParser()}
1807    *       </ul>
1808    *    <li><b>Methods:</b>
1809    *       <ul>
1810    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#partParser(Class)}
1811    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#partParser(HttpPartParser)}
1812    *       </ul>
1813    * </ul>
1814    *
1815    * <h5 class='section'>Description:</h5>
1816    * <p>
1817    * Specifies the {@link HttpPartParser} to use for parsing headers, query/form parameters, and URI parts.
1818    *
1819    * <p>
1820    * The default value is {@link OpenApiParser} which allows for both plain-text and URL-Encoded-Object-Notation values.
1821    * <br>If your parts contain text that can be confused with UON (e.g. <js>"(foo)"</js>), you can switch to
1822    * {@link SimplePartParser} which treats everything as plain text.
1823    *
1824    * <h5 class='section'>Example:</h5>
1825    * <p class='bcode w800'>
1826    *    <jc>// Option #1 - Defined via annotation.</jc>
1827    *    <ja>@Rest</ja>(partParser=SimplePartParser.<jk>class</jk>)
1828    *    <jk>public class</jk> MyResource {
1829    *
1830    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1831    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1832    *
1833    *          <jc>// Using method on builder.</jc>
1834    *          builder.partParser(SimplePartParser.<jk>class</jk>);
1835    *
1836    *          <jc>// Same, but using property.</jc>
1837    *          builder.set(<jsf>REST_partParser</jsf>, SimplePartParser.<jk>class</jk>);
1838    *       }
1839    *
1840    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1841    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1842    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1843    *          builder.partParser(SimplePartParser.<jk>class</jk>);
1844    *       }
1845    *
1846    *       <ja>@RestMethod</ja>(...)
1847    *       <jk>public</jk> Object myMethod(<ja>@Header</ja>(<js>"My-Header"</js>) MyParsedHeader h, <ja>@Query</ja>(<js>"myquery"</js>) MyParsedQuery q) {
1848    *          <jc>// Do something with your parsed parts.</jc>
1849    *       }
1850    *    }
1851    * </p>
1852    *
1853    * <ul class='notes'>
1854    *    <li>
1855    *       When defined as a class, properties/transforms defined on the resource/method are inherited.
1856    *    <li>
1857    *       When defined as an instance, properties/transforms defined on the resource/method are NOT inherited.
1858    * </ul>
1859    */
1860   public static final String REST_partParser = PREFIX + ".partParser.o";
1861
1862   /**
1863    * Configuration property:  HTTP part serializer.
1864    *
1865    * <h5 class='section'>Property:</h5>
1866    * <ul class='spaced-list'>
1867    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_partSerializer REST_partSerializer}
1868    *    <li><b>Name:</b>  <js>"RestContext.partSerializer.o"</js>
1869    *    <li><b>Data type:</b>
1870    *       <ul>
1871    *          <li>{@link org.apache.juneau.httppart.HttpPartSerializer}
1872    *          <li><c>Class&lt;{@link org.apache.juneau.httppart.HttpPartSerializer}&gt;</c>
1873    *       </ul>
1874    *    <li><b>Default:</b>  {@link org.apache.juneau.oapi.OpenApiSerializer}
1875    *    <li><b>Session property:</b>  <jk>false</jk>
1876    *    <li><b>Annotations:</b>
1877    *       <ul>
1878    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#partSerializer()}
1879    *       </ul>
1880    *    <li><b>Methods:</b>
1881    *       <ul>
1882    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#partSerializer(Class)}
1883    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#partSerializer(HttpPartSerializer)}
1884    *       </ul>
1885    * </ul>
1886    *
1887    * <h5 class='section'>Description:</h5>
1888    * <p>
1889    * Specifies the {@link HttpPartSerializer} to use for serializing headers, query/form parameters, and URI parts.
1890    *
1891    * <p>
1892    * The default value is {@link OpenApiSerializer} which serializes based on OpenAPI rules, but defaults to UON notation for beans and maps, and
1893    * plain text for everything else.
1894    * <br>Other options include:
1895    * <ul>
1896    *    <li class='jc'>{@link SimplePartSerializer} - Always serializes to plain text.
1897    *    <li class='jc'>{@link UonSerializer} - Always serializers to UON.
1898    * </ul>
1899    *
1900    * <h5 class='section'>Example:</h5>
1901    * <p class='bcode w800'>
1902    *    <jc>// Option #1 - Defined via annotation.</jc>
1903    *    <ja>@Rest</ja>(partSerializer=SimplePartSerializer.<jk>class</jk>)
1904    *    <jk>public class</jk> MyResource {
1905    *
1906    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1907    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1908    *
1909    *          <jc>// Using method on builder.</jc>
1910    *          builder.partSerializer(SimplePartSerializer.<jk>class</jk>);
1911    *
1912    *          <jc>// Same, but using property.</jc>
1913    *          builder.set(<jsf>REST_partSerializer</jsf>, SimplePartSerializer.<jk>class</jk>);
1914    *       }
1915    *
1916    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1917    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1918    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1919    *          builder.partSerializer(SimplePartSerializer.<jk>class</jk>);
1920    *       }
1921    *
1922    *       <ja>@RestMethod</ja>(...)
1923    *       <jk>public</jk> Object myMethod(RestResponse res) {
1924    *          <jc>// Set a header to a POJO.</jc>
1925    *          res.setHeader(<js>"My-Header"</js>, <jk>new</jk> MyPojo());
1926    *       }
1927    *    }
1928    * </p>
1929    *
1930    * <ul class='notes'>
1931    *    <li>
1932    *       When defined as a class, properties/transforms defined on the resource/method are inherited.
1933    *    <li>
1934    *       When defined as an instance, properties/transforms defined on the resource/method are NOT inherited.
1935    * </ul>
1936    */
1937   public static final String REST_partSerializer = PREFIX + ".partSerializer.o";
1938
1939   /**
1940    * Configuration property:  Resource path.
1941    *
1942    * <h5 class='section'>Property:</h5>
1943    * <ul class='spaced-list'>
1944    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_path REST_path}
1945    *    <li><b>Name:</b>  <js>"RestContext.path.s"</js>
1946    *    <li><b>Data type:</b>  <c>String</c>
1947    *    <li><b>System property:</b>  <c>RestContext.path.</c>
1948    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_PATH</c>
1949    *    <li><b>Default:</b>  <jk>null</jk>
1950    *    <li><b>Session property:</b>  <jk>false</jk>
1951    *    <li><b>Annotations:</b>
1952    *       <ul>
1953    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#path()}
1954    *       </ul>
1955    *    <li><b>Methods:</b>
1956    *       <ul>
1957    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#path(String)}
1958    *       </ul>
1959    * </ul>
1960    *
1961    * <h5 class='section'>Description:</h5>
1962    * <p>
1963    * Identifies the URL subpath relative to the ascendant resource.
1964    *
1965    * <p>
1966    * This setting is critical for the routing of HTTP requests from ascendant to child resources.
1967    *
1968    * <h5 class='section'>Example:</h5>
1969    * <p class='bcode w800'>
1970    *    <jc>// Option #1 - Defined via annotation.</jc>
1971    *    <ja>@Rest</ja>(path=<js>"/myResource"</js>)
1972    *    <jk>public class</jk> MyResource {
1973    *
1974    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1975    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
1976    *
1977    *          <jc>// Using method on builder.</jc>
1978    *          builder.path(<js>"/myResource"</js>);
1979    *
1980    *          <jc>// Same, but using property.</jc>
1981    *          builder.set(<jsf>REST_path</jsf>, <js>"/myResource"</js>);
1982    *       }
1983    *
1984    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1985    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
1986    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
1987    *          builder.path(<js>"/myResource"</js>);
1988    *       }
1989    *    }
1990    * </p>
1991    *
1992    * <p>
1993    * <ul class='notes'>
1994    *    <li>
1995    *       This annotation is ignored on top-level servlets (i.e. servlets defined in <c>web.xml</c> files).
1996    *       <br>Therefore, implementers can optionally specify a path value for documentation purposes.
1997    *    <li>
1998    *       Typically, this setting is only applicable to resources defined as children through the
1999    *       {@link Rest#children() @Rest(children)} annotation.
2000    *       <br>However, it may be used in other ways (e.g. defining paths for top-level resources in microservices).
2001    *    <li>
2002    *       Slashes are trimmed from the path ends.
2003    *       <br>As a convention, you may want to start your path with <js>'/'</js> simple because it make it easier to read.
2004    *    <li>
2005    *       This path is available through the following method:
2006    *       <ul>
2007    *          <li class='jm'>{@link RestContext#getPath() RestContext.getPath()}
2008    *       </ul>
2009    * </ul>
2010    */
2011   public static final String REST_path = PREFIX + ".path.s";
2012
2013   /**
2014    * Configuration property:  Render response stack traces in responses.
2015    *
2016    * <h5 class='section'>Property:</h5>
2017    * <ul class='spaced-list'>
2018    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_renderResponseStackTraces REST_renderResponseStackTraces}
2019    *    <li><b>Name:</b>  <js>"RestContext.renderResponseStackTraces.b"</js>
2020    *    <li><b>Data type:</b>  <jk>boolean</jk>
2021    *    <li><b>System property:</b>  <c>RestContext.renderResponseStackTraces</c>
2022    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_RENDERRESPONSESTACKTRACES</c>
2023    *    <li><b>Default:</b>  <jk>false</jk>
2024    *    <li><b>Session property:</b>  <jk>false</jk>
2025    *    <li><b>Annotations:</b>
2026    *       <ul>
2027    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#renderResponseStackTraces()}
2028    *       </ul>
2029    *    <li><b>Methods:</b>
2030    *       <ul>
2031    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#renderResponseStackTraces(boolean)}
2032    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#renderResponseStackTraces()}
2033    *       </ul>
2034    * </ul>
2035    *
2036    * <h5 class='section'>Description:</h5>
2037    * <p>
2038    * Render stack traces in HTTP response bodies when errors occur.
2039    *
2040    * <h5 class='section'>Example:</h5>
2041    * <p class='bcode w800'>
2042    *    <jc>// Option #1 - Defined via annotation.</jc>
2043    *    <ja>@Rest</ja>(renderResponseStackTraces=<jk>true</jk>)
2044    *    <jk>public class</jk> MyResource {
2045    *
2046    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2047    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2048    *
2049    *          <jc>// Using method on builder.</jc>
2050    *          builder.renderResponseStackTraces();
2051    *
2052    *          <jc>// Same, but using property.</jc>
2053    *          builder.set(<jsf>REST_renderResponseStackTraces</jsf>, <jk>true</jk>);
2054    *       }
2055    *
2056    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2057    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2058    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2059    *          builder.renderResponseStackTraces();
2060    *       }
2061    *    }
2062    * </p>
2063    *
2064    * <ul class='notes'>
2065    *    <li>
2066    *       Useful for debugging, although allowing stack traces to be rendered may cause security concerns so use
2067    *       caution when enabling.
2068    *    <li>
2069    *       This setting is available through the following method:
2070    *       <ul>
2071    *          <li class='jm'>{@link RestContext#isRenderResponseStackTraces() RestContext.isRenderResponseStackTraces()}
2072    *       </ul>
2073    *       That method is used by {@link BasicRestCallHandler#handleError(RestCall, Throwable)}.
2074    * </ul>
2075    */
2076   public static final String REST_renderResponseStackTraces = PREFIX + ".renderResponseStackTraces.b";
2077
2078   /**
2079    * Configuration property:  Default request attributes.
2080    *
2081    * <h5 class='section'>Property:</h5>
2082    * <ul class='spaced-list'>
2083    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_reqAttrs REST_reqAttrs}
2084    *    <li><b>Name:</b>  <js>"RestContext.reqAttrs.smo"</js>
2085    *    <li><b>Data type:</b>  <c>Map&lt;String,Object&gt;</c>
2086    *    <li><b>System property:</b>  <c>RestContext.reqAttrs</c>
2087    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_REQATTRS</c>
2088    *    <li><b>Default:</b>  empty map
2089    *    <li><b>Session property:</b>  <jk>false</jk>
2090    *    <li><b>Annotations:</b>
2091    *       <ul>
2092    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#reqAttrs()}
2093    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#reqAttrs()}
2094    *       </ul>
2095    *    <li><b>Methods:</b>
2096    *       <ul>
2097    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#reqAttrs(String...)}
2098    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#reqAttr(String,Object)}
2099    *       </ul>
2100    * </ul>
2101    *
2102    * <h5 class='section'>Description:</h5>
2103    * <p>
2104    * Specifies default values for request attributes if they're not already set on the request.
2105    *
2106    * <ul class='notes'>
2107    *    <li>
2108    *       Strings are in the format <js>"Name: value"</js>.
2109    *    <li>
2110    *       Affects values returned by the following methods:
2111    *       <ul>
2112    *          <li class='jm'>{@link RestRequest#getAttribute(String)}.
2113    *          <li class='jm'>{@link RestRequest#getAttributes()}.
2114    *       </ul>
2115    * </ul>
2116    *
2117    * <h5 class='section'>Example:</h5>
2118    * <p class='bcode w800'>
2119    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
2120    *    <ja>@Rest</ja>(reqAttrs={<js>"Foo: bar"</js>, <js>"Baz: $C{REST/myAttributeValue}"</js>})
2121    *    <jk>public class</jk> MyResource {
2122    *
2123    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2124    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2125    *
2126    *          <jc>// Using method on builder.</jc>
2127    *          builder
2128    *             .attr(<js>"Foo"</js>, <js>"bar"</js>);
2129    *             .attr(<js>"Baz: true"</js>);
2130    *
2131    *          <jc>// Same, but using property.</jc>
2132    *          builder.addTo(<jsf>REST_reqAttrs</jsf>, <js>"Foo"</js>, <js>"bar"</js>);
2133    *       }
2134    *
2135    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2136    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2137    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2138    *          builder.reqAttr(<js>"Foo"</js>, <js>"bar"</js>);
2139    *       }
2140    *
2141    *       <jc>// Override at the method level.</jc>
2142    *       <ja>@RestMethod</ja>(reqAttrs={<js>"Foo: bar"</js>})
2143    *       public Object myMethod() {...}
2144    *    }
2145    * </p>
2146    */
2147   public static final String REST_reqAttrs = PREFIX + ".reqAttrs.smo";
2148
2149   /**
2150    * Configuration property:  Default request headers.
2151    *
2152    * <h5 class='section'>Property:</h5>
2153    * <ul class='spaced-list'>
2154    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_reqHeaders REST_reqHeaders}
2155    *    <li><b>Name:</b>  <js>"RestContext.reqHeaders.smo"</js>
2156    *    <li><b>Data type:</b>  <c>Map&lt;String,String&gt;</c>
2157    *    <li><b>System property:</b>  <c>RestContext.reqHeaders</c>
2158    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_REQHEADERS</c>
2159    *    <li><b>Default:</b>  empty map
2160    *    <li><b>Session property:</b>  <jk>false</jk>
2161    *    <li><b>Annotations:</b>
2162    *       <ul>
2163    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#reqHeaders()}
2164    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#reqHeaders()}
2165    *       </ul>
2166    *    <li><b>Methods:</b>
2167    *       <ul>
2168    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#reqHeader(String,Object)}
2169    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#reqHeaders(String...)}
2170    *       </ul>
2171    * </ul>
2172    *
2173    * <h5 class='section'>Description:</h5>
2174    * <p>
2175    * Specifies default values for request headers if they're not passed in through the request.
2176    *
2177    * <ul class='notes'>
2178    *    <li>
2179    *       Strings are in the format <js>"Header-Name: header-value"</js>.
2180    *    <li>
2181    *       Affects values returned by {@link RestRequest#getHeader(String)} when the header is not present on the request.
2182    *    <li>
2183    *       The most useful reason for this annotation is to provide a default <c>Accept</c> header when one is not
2184    *       specified so that a particular default {@link Serializer} is picked.
2185    * </ul>
2186    *
2187    * <h5 class='section'>Example:</h5>
2188    * <p class='bcode w800'>
2189    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
2190    *    <ja>@Rest</ja>(reqHeaders={<js>"Accept: application/json"</js>, <js>"My-Header: $C{REST/myHeaderValue}"</js>})
2191    *    <jk>public class</jk> MyResource {
2192    *
2193    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2194    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2195    *
2196    *          <jc>// Using method on builder.</jc>
2197    *          builder
2198    *             .reqHeader(<js>"Accept"</js>, <js>"application/json"</js>);
2199    *             .reqHeaders(<js>"My-Header: foo"</js>);
2200    *
2201    *          <jc>// Same, but using property.</jc>
2202    *          builder.addTo(<jsf>REST_reqHeaders</jsf>, <js>"Accept"</js>, <js>"application/json"</js>);
2203    *       }
2204    *
2205    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2206    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2207    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2208    *          builder.reqHeader(<js>"Accept"</js>, <js>"application/json"</js>);
2209    *       }
2210    *
2211    *       <jc>// Override at the method level.</jc>
2212    *       <ja>@RestMethod</ja>(reqHeaders={<js>"Accept: text/xml"</js>})
2213    *       public Object myMethod() {...}
2214    *    }
2215    * </p>
2216    */
2217   public static final String REST_reqHeaders = PREFIX + ".reqHeaders.smo";
2218
2219   /**
2220    * Configuration property:  Default response headers.
2221    *
2222    * <h5 class='section'>Property:</h5>
2223    * <ul class='spaced-list'>
2224    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_resHeaders REST_resHeaders}
2225    *    <li><b>Name:</b>  <js>"RestContext.resHeaders.omo"</js>
2226    *    <li><b>Data type:</b>  <c>Map&lt;String,String&gt;</c>
2227    *    <li><b>System property:</b>  <c>RestContext.resHeaders</c>
2228    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_RESHEADERS</c>
2229    *    <li><b>Default:</b>  empty map
2230    *    <li><b>Session property:</b>  <jk>false</jk>
2231    *    <li><b>Annotations:</b>
2232    *       <ul>
2233    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#resHeaders()}
2234    *       </ul>
2235    *    <li><b>Methods:</b>
2236    *       <ul>
2237    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#resHeader(String,Object)}
2238    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#resHeaders(String...)}
2239    *       </ul>
2240    * </ul>
2241    *
2242    * <h5 class='section'>Description:</h5>
2243    * <p>
2244    * Specifies default values for response headers if they're not set after the Java REST method is called.
2245    *
2246    * <ul class='notes'>
2247    *    <li>
2248    *       Strings are in the format <js>"Header-Name: header-value"</js>.
2249    *    <li>
2250    *       This is equivalent to calling {@link RestResponse#setHeader(String, String)} programmatically in each of
2251    *       the Java methods.
2252    *    <li>
2253    *       The header value will not be set if the header value has already been specified (hence the 'default' in the name).
2254    * </ul>
2255    *
2256    * <h5 class='section'>Example:</h5>
2257    * <p class='bcode w800'>
2258    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
2259    *    <ja>@Rest</ja>(resHeaders={<js>"Content-Type: $C{REST/defaultContentType,text/plain}"</js>,<js>"My-Header: $C{REST/myHeaderValue}"</js>})
2260    *    <jk>public class</jk> MyResource {
2261    *
2262    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2263    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2264    *
2265    *          <jc>// Using method on builder.</jc>
2266    *          builder
2267    *             .resHeader(<js>"Content-Type"</js>, <js>"text/plain"</js>);
2268    *             .resHeaders(<js>"My-Header: foo"</js>);
2269    *
2270    *          <jc>// Same, but using property.</jc>
2271    *          builder
2272    *             .addTo(<jsf>REST_resHeaders</jsf>, <js>"Accept"</js>, <js>"application/json"</js>);
2273    *             .addTo(<jsf>REST_resHeaders</jsf>, <js>"My-Header"</js>, <js>"foo"</js>);
2274    *       }
2275    *
2276    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2277    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2278    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2279    *          builder.resHeader(<js>"Content-Type"</js>, <js>"text/plain"</js>);
2280    *       }
2281    *    }
2282    * </p>
2283    */
2284   public static final String REST_resHeaders = PREFIX + ".resHeaders.omo";
2285
2286   /**
2287    * Configuration property:  REST resource resolver.
2288    *
2289    * <h5 class='section'>Property:</h5>
2290    * <ul class='spaced-list'>
2291    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_resourceResolver REST_resourceResolver}
2292    *    <li><b>Name:</b>  <js>"RestContext.resourceResolver.o"</js>
2293    *    <li><b>Data type:</b>
2294    *       <ul>
2295    *          <li>{@link org.apache.juneau.rest.RestResourceResolver}
2296    *          <li><c>Class&lt;{@link org.apache.juneau.rest.RestResourceResolver}&gt;</c>
2297    *       </ul>
2298    *    <li><b>Default:</b>  {@link org.apache.juneau.rest.BasicRestResourceResolver}
2299    *    <li><b>Session property:</b>  <jk>false</jk>
2300    *    <li><b>Annotations:</b>
2301    *       <ul>
2302    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#resourceResolver()}
2303    *       </ul>
2304    *    <li><b>Methods:</b>
2305    *       <ul>
2306    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#resourceResolver(Class)}
2307    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#resourceResolver(RestResourceResolver)}
2308    *       </ul>
2309    * </ul>
2310    *
2311    * <h5 class='section'>Description:</h5>
2312    * <p>
2313    * The resolver used for resolving instances of child resources.
2314    *
2315    * <p>
2316    * Can be used to provide customized resolution of REST resource class instances (e.g. resources retrieve from Spring).
2317    *
2318    * <h5 class='section'>Example:</h5>
2319    * <p class='bcode w800'>
2320    *    <jc>// Our custom resource resolver. </jc>
2321    *    <jk>public class</jk> MyResourceResolver <jk>extends</jk> RestResourceResolverSimple {
2322    *
2323    *       <ja>@Override</ja>
2324    *       <jk>public</jk> Object resolve(Class&lt;?&gt; resourceType, RestContextBuilder builder) <jk>throws</jk> Exception {
2325    *          Object resource = <jsm>findOurResourceSomehow</jsm>(resourceType);
2326    *
2327    *          <jc>// If we can't resolve it, use default resolution.</jc>
2328    *          <jk>if</jk> (resource == <jk>null</jk>)
2329    *             resource = <jk>super</jk>.resolve(resourceType, builder);
2330    *
2331    *          <jk>return</jk> resource;
2332    *       }
2333    *    }
2334    *
2335    *    <jc>// Option #1 - Defined via annotation.</jc>
2336    *    <ja>@Rest</ja>(resourceResolver=MyResourceResolver.<jk>class</jk>)
2337    *    <jk>public class</jk> MyResource {
2338    *
2339    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2340    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2341    *
2342    *          <jc>// Using method on builder.</jc>
2343    *          builder.resourceResolver(MyResourceResolver.<jk>class</jk>);
2344    *
2345    *          <jc>// Same, but using property.</jc>
2346    *          builder.set(<jsf>REST_resourceResolver</jsf>, MyResourceResolver.<jk>class</jk>);
2347    *       }
2348    *
2349    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2350    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2351    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2352    *          builder.resourceResolver(MyResourceResolver.<jk>class</jk>);
2353    *       }
2354    *    }
2355    * </p>
2356    *
2357    * <ul class='notes'>
2358    *    <li>
2359    *       Unless overridden, resource resolvers are inherited from ascendant resources.
2360    *    <li>
2361    *       When defined as a class, the implementation must have one of the following constructors:
2362    *       <ul>
2363    *          <li><code><jk>public</jk> T(RestContext)</code>
2364    *          <li><code><jk>public</jk> T()</code>
2365    *       </ul>
2366    *    <li>
2367    *       Inner classes of the REST resource class are allowed.
2368    * </ul>
2369    *
2370    * <ul class='seealso'>
2371    *    <li class='link'>{@doc juneau-rest-server.Instantiation.ResourceResolvers}
2372    *    <li class='link'>{@doc juneau-rest-server.Injection}
2373    * </ul>
2374    */
2375   public static final String REST_resourceResolver = PREFIX + ".resourceResolver.o";
2376
2377   /**
2378    * Configuration property:  Response handlers.
2379    *
2380    * <h5 class='section'>Property:</h5>
2381    * <ul class='spaced-list'>
2382    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_responseHandlers REST_responseHandlers}
2383    *    <li><b>Name:</b>  <js>"RestContext.responseHandlers.lo"</js>
2384    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.rest.ResponseHandler}|Class&lt;{@link org.apache.juneau.rest.ResponseHandler}&gt;&gt;</c>
2385    *    <li><b>Default:</b>  empty list
2386    *    <li><b>Session property:</b>  <jk>false</jk>
2387    *    <li><b>Annotations:</b>
2388    *       <ul>
2389    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#responseHandlers()}
2390    *       </ul>
2391    *    <li><b>Methods:</b>
2392    *       <ul>
2393    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#responseHandlers(Class...)}
2394    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#responseHandlers(ResponseHandler...)}
2395    *       </ul>
2396    * </ul>
2397    *
2398    * <h5 class='section'>Description:</h5>
2399    * <p>
2400    * Specifies a list of {@link ResponseHandler} classes that know how to convert POJOs returned by REST methods or
2401    * set via {@link RestResponse#setOutput(Object)} into appropriate HTTP responses.
2402    *
2403    * <p>
2404    * By default, the following response handlers are provided out-of-the-box:
2405    * <ul>
2406    *    <li class='jc'>{@link ReaderHandler} - {@link Reader} objects.
2407    *    <li class='jc'>{@link InputStreamHandler} - {@link InputStream} objects.
2408    *    <li class='jc'>{@link DefaultHandler} - All other POJOs.
2409    * </ul>
2410    *
2411    * <h5 class='section'>Example:</h5>
2412    * <p class='bcode w800'>
2413    *    <jc>// Our custom response handler for MySpecialObject objects. </jc>
2414    *    <jk>public class</jk> MyResponseHandler <jk>implements</jk> ResponseHandler {
2415    *
2416    *       <ja>@Override</ja>
2417    *       <jk>public boolean</jk> handle(RestRequest req, RestResponse res, Object output) <jk>throws</jk> IOException, RestException {
2418    *          <jk>if</jk> (output <jk>instanceof</jk> MySpecialObject) {
2419    *             <jk>try</jk> (Writer w = res.getNegotiatedWriter()) {
2420    *                <jc>//Pipe it to the writer ourselves.</jc>
2421    *             }
2422    *             <jk>return true</jk>;  <jc>// We handled it.</jc>
2423    *          }
2424    *          <jk>return false</jk>; <jc>// We didn't handle it.</jc>
2425    *       }
2426    *    }
2427    *
2428    *    <jc>// Option #1 - Defined via annotation.</jc>
2429    *    <ja>@Rest</ja>(responseHandlers=MyResponseHandler.<jk>class</jk>)
2430    *    <jk>public class</jk> MyResource {
2431    *
2432    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2433    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2434    *
2435    *          <jc>// Using method on builder.</jc>
2436    *          builder.responseHandlers(MyResponseHandler.<jk>class</jk>);
2437    *
2438    *          <jc>// Same, but using property.</jc>
2439    *          builder.addTo(<jsf>REST_responseHandlers</jsf>, MyResponseHandler.<jk>class</jk>);
2440    *       }
2441    *
2442    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2443    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2444    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2445    *          builder.responseHandlers(MyResponseHandler.<jk>class</jk>);
2446    *       }
2447    *
2448    *       <ja>@RestMethod</ja>(...)
2449    *       <jk>public</jk> Object myMethod() {
2450    *          <jc>// Return a special object for our handler.</jc>
2451    *          <jk>return new</jk> MySpecialObject();
2452    *       }
2453    *    }
2454    * </p>
2455    *
2456    * <ul class='notes'>
2457    *    <li>
2458    *       Response handlers resolvers are always inherited from ascendant resources.
2459    *    <li>
2460    *       When defined as a class, the implementation must have one of the following constructors:
2461    *       <ul>
2462    *          <li><code><jk>public</jk> T(RestContext)</code>
2463    *          <li><code><jk>public</jk> T()</code>
2464    *       </ul>
2465    *    <li>
2466    *       Inner classes of the REST resource class are allowed.
2467    * </ul>
2468    */
2469   public static final String REST_responseHandlers = PREFIX + ".responseHandlers.lo";
2470
2471   /**
2472    * Configuration property:  Declared roles.
2473    *
2474    * <h5 class='section'>Property:</h5>
2475    * <ul class='spaced-list'>
2476    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_rolesDeclared REST_rolesDeclared}
2477    *    <li><b>Name:</b>  <js>"RestContext.rolesDeclared.ss"</js>
2478    *    <li><b>Data type:</b>  <c>Set&lt;String&gt;</c>
2479    *    <li><b>System property:</b>  <c>RestContext.rolesDeclared</c>
2480    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_ROLESDECLARED</c>
2481    *    <li><b>Default:</b>  empty list
2482    *    <li><b>Session property:</b>  <jk>false</jk>
2483    *    <li><b>Annotations:</b>
2484    *       <ul>
2485    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#rolesDeclared()}
2486    *       </ul>
2487    *    <li><b>Methods:</b>
2488    *       <ul>
2489    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#rolesDeclared(String...)}
2490    *       </ul>
2491    * </ul>
2492    *
2493    *
2494    * <h5 class='section'>Description:</h5>
2495    * <p>
2496    * A comma-delimited list of all possible user roles.
2497    *
2498    * <p>
2499    * Used in conjunction with {@link RestContextBuilder#roleGuard(String)} is used with patterns.
2500    *
2501    * <h5 class='section'>Example:</h5>
2502    * <p class='bcode w800'>
2503    *    <ja>@Rest</ja>(
2504    *       rolesDeclared=<js>"ROLE_ADMIN,ROLE_READ_WRITE,ROLE_READ_ONLY,ROLE_SPECIAL"</js>,
2505    *       roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
2506    *    )
2507    *    <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
2508    *       ...
2509    *    }
2510    * </p>
2511    *
2512    * <ul class='seealso'>
2513    *    <li class='jf'>{@link RestContext#REST_rolesDeclared}
2514    * </ul>
2515    */
2516   public static final String REST_rolesDeclared = PREFIX + ".rolesDeclared.ss";
2517
2518   /**
2519    * Configuration property:  Role guard.
2520    *
2521    * <h5 class='section'>Property:</h5>
2522    * <ul class='spaced-list'>
2523    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_roleGuard REST_roleGuard}
2524    *    <li><b>Name:</b>  <js>"RestContext.roleGuard.ss"</js>
2525    *    <li><b>Data type:</b>  <c>Set&lt;String&gt;</c>
2526    *    <li><b>System property:</b>  <c>RestContext.roleGuard</c>
2527    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_ROLEGUARD</c>
2528    *    <li><b>Default:</b>  empty set
2529    *    <li><b>Session property:</b>  <jk>false</jk>
2530    *    <li><b>Annotations:</b>
2531    *       <ul>
2532    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#roleGuard()}
2533    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#roleGuard()}
2534    *       </ul>
2535    *    <li><b>Methods:</b>
2536    *       <ul>
2537    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#roleGuard(String)}
2538    *       </ul>
2539    * </ul>
2540    *
2541    * <h5 class='section'>Description:</h5>
2542    * <p>
2543    * An expression defining if a user with the specified roles are allowed to access methods on this class.
2544    *
2545    * <h5 class='section'>Example:</h5>
2546    * <p class='bcode w800'>
2547    *    <ja>@Rest</ja>(
2548    *       path=<js>"/foo"</js>,
2549    *       roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
2550    *    )
2551    *    <jk>public class</jk> MyResource <jk>extends</jk> RestServlet {
2552    *       ...
2553    *    }
2554    * </p>
2555    *
2556    * <ul class='notes'>
2557    *    <li>
2558    *       Supports any of the following expression constructs:
2559    *       <ul>
2560    *          <li><js>"foo"</js> - Single arguments.
2561    *          <li><js>"foo,bar,baz"</js> - Multiple OR'ed arguments.
2562    *          <li><js>"foo | bar | bqz"</js> - Multiple OR'ed arguments, pipe syntax.
2563    *          <li><js>"foo || bar || bqz"</js> - Multiple OR'ed arguments, Java-OR syntax.
2564    *          <li><js>"fo*"</js> - Patterns including <js>'*'</js> and <js>'?'</js>.
2565    *          <li><js>"fo* &amp; *oo"</js> - Multiple AND'ed arguments, ampersand syntax.
2566    *          <li><js>"fo* &amp;&amp; *oo"</js> - Multiple AND'ed arguments, Java-AND syntax.
2567    *          <li><js>"fo* || (*oo || bar)"</js> - Parenthesis.
2568    *       </ul>
2569    *    <li>
2570    *       AND operations take precedence over OR operations (as expected).
2571    *    <li>
2572    *       Whitespace is ignored.
2573    *    <li>
2574    *       <jk>null</jk> or empty expressions always match as <jk>false</jk>.
2575    *    <li>
2576    *       If patterns are used, you must specify the list of declared roles using {@link Rest#rolesDeclared()} or {@link RestContext#REST_rolesDeclared}.
2577    *    <li>
2578    *       Supports {@doc DefaultRestSvlVariables}
2579    *       (e.g. <js>"$L{my.localized.variable}"</js>).
2580    *    <li>
2581    *       Role guards defined at both the class and method level must both pass.
2582    * </ul>
2583    *
2584    * <ul class='seealso'>
2585    *    <li class='jf'>{@link RestContext#REST_roleGuard}
2586    * </ul>
2587    */
2588   public static final String REST_roleGuard = PREFIX + ".roleGuard.ss";
2589
2590   /**
2591    * Configuration property:  Serializers.
2592    *
2593    * <h5 class='section'>Property:</h5>
2594    * <ul class='spaced-list'>
2595    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_serializers REST_serializers}
2596    *    <li><b>Name:</b>  <js>"RestContext.serializers.lo"</js>
2597    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.serializer.Serializer}|Class&lt;{@link org.apache.juneau.serializer.Serializer}&gt;&gt;</c>
2598    *    <li><b>Default:</b>  empty list
2599    *    <li><b>Session property:</b>  <jk>false</jk>
2600    *    <li><b>Annotations:</b>
2601    *       <ul>
2602    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#serializers()}
2603    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#serializers()}
2604    *       </ul>
2605    *    <li><b>Methods:</b>
2606    *       <ul>
2607    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#serializers(Object...)}
2608    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#serializers(Class...)}
2609    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#serializersReplace(Object...)}
2610    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#serializersReplace(Class...)}
2611    *       </ul>
2612    * </ul>
2613    *
2614    * <h5 class='section'>Description:</h5>
2615    * <p>
2616    * Adds class-level serializers to this resource.
2617    *
2618    * <p>
2619    * Serializer are used to convert POJOs to HTTP response bodies.
2620    * <br>Any of the Juneau framework serializers can be used in this setting.
2621    * <br>The serializer selected is based on the request <c>Accept</c> header matched against the values returned by the following method
2622    * using a best-match algorithm:
2623    * <ul class='javatree'>
2624    *    <li class='jm'>{@link Serializer#getMediaTypeRanges()}
2625    * </ul>
2626    *
2627    * <h5 class='section'>Example:</h5>
2628    * <p class='bcode w800'>
2629    *    <jc>// Option #1 - Defined via annotation.</jc>
2630    *    <ja>@Rest</ja>(serializers={JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>})
2631    *    <jk>public class</jk> MyResource {
2632    *
2633    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2634    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2635    *
2636    *          <jc>// Using method on builder.</jc>
2637    *          builder.serializers(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>);
2638    *
2639    *          <jc>// Same, but use pre-instantiated parsers.</jc>
2640    *          builder.serializers(JsonSerializer.<jsf>DEFAULT</jsf>, XmlSerializer.<jsf>DEFAULT</jsf>);
2641    *
2642    *          <jc>// Same, but using property.</jc>
2643    *          builder.set(<jsf>REST_serializers</jsf>, JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>);
2644    *       }
2645    *
2646    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2647    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2648    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2649    *          builder.serializers(JsonSerializer.<jk>class</jk>, XmlSerializer.<jk>class</jk>);
2650    *       }
2651    *
2652    *       <jc>// Override at the method level.</jc>
2653    *       <ja>@RestMethod</ja>(serializers={HtmlSerializer.<jk>class</jk>})
2654    *       <jk>public</jk> MyPojo myMethod() {
2655    *          <jc>// Return a POJO to be serialized.</jc>
2656    *          <jk>return new</jk> MyPojo();
2657    *       }
2658    *    }
2659    * </p>
2660    *
2661    * <ul class='notes'>
2662    *    <li>
2663    *       When defined as a class, properties/transforms defined on the resource/method are inherited.
2664    *    <li>
2665    *       When defined as an instance, properties/transforms defined on the resource/method are NOT inherited.
2666    *    <li>
2667    *       Typically, you'll want your resource to extend directly from {@link BasicRestServlet} which comes
2668    *       preconfigured with the following serializers:
2669    *       <ul>
2670    *          <li class='jc'>{@link HtmlDocSerializer}
2671    *          <li class='jc'>{@link HtmlStrippedDocSerializer}
2672    *          <li class='jc'>{@link HtmlSchemaDocSerializer}
2673    *          <li class='jc'>{@link JsonSerializer}
2674    *          <li class='jc'>{@link SimpleJsonSerializer}
2675    *          <li class='jc'>{@link JsonSchemaSerializer}
2676    *          <li class='jc'>{@link XmlDocSerializer}
2677    *          <li class='jc'>{@link XmlSchemaDocSerializer}
2678    *          <li class='jc'>{@link UonSerializer}
2679    *          <li class='jc'>{@link UrlEncodingSerializer}
2680    *          <li class='jc'>{@link MsgPackSerializer}
2681    *          <li class='jc'>{@link SoapXmlSerializer}
2682    *          <li class='jc'>{@link PlainTextSerializer}
2683    *       </ul>
2684    * </ul>
2685    *
2686    * <ul class='seealso'>
2687    *    <li class='link'>{@doc juneau-rest-server.Serializers}
2688    * </ul>
2689    * <p>
2690    */
2691   public static final String REST_serializers = PREFIX + ".serializers.lo";
2692
2693   /**
2694    * Configuration property:  Static file response headers.
2695    *
2696    * <h5 class='section'>Property:</h5>
2697    * <ul class='spaced-list'>
2698    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_staticFileResponseHeaders REST_staticFileResponseHeaders}
2699    *    <li><b>Name:</b>  <js>"RestContext.staticFileResponseHeaders.omo"</js>
2700    *    <li><b>Data type:</b>  <c>Map&lt;String,String&gt;</c>
2701    *    <li><b>System property:</b>  <c>RestContext.staticFileResponseHeaders</c>
2702    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_STATICFILERESPONSEHEADERS</c>
2703    *    <li><b>Default:</b>  <code>{<js>'Cache-Control'</js>: <js>'max-age=86400, public</js>}</code>
2704    *    <li><b>Session property:</b>  <jk>false</jk>
2705    *    <li><b>Annotations:</b>
2706    *       <ul>
2707    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#staticFileResponseHeaders()}
2708    *       </ul>
2709    *    <li><b>Methods:</b>
2710    *       <ul>
2711    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFileResponseHeaders(Map)}
2712    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFileResponseHeaders(String...)}
2713    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFileResponseHeader(String,String)}
2714    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFileResponseHeadersReplace(Map)}
2715    *       </ul>
2716    * </ul>
2717    *
2718    * <h5 class='section'>Description:</h5>
2719    * <p>
2720    * Used to customize the headers on responses returned for statically-served files.
2721    *
2722    * <h5 class='section'>Example:</h5>
2723    * <p class='bcode w800'>
2724    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
2725    *    <ja>@Rest</ja>(
2726    *       staticFileResponseHeaders={
2727    *          <js>"Cache-Control: $C{REST/cacheControl,nocache}"</js>,
2728    *          <js>"My-Header: $C{REST/myHeaderValue}"</js>
2729    *       }
2730    *    )
2731    *    <jk>public class</jk> MyResource {
2732    *
2733    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2734    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2735    *
2736    *          <jc>// Using method on builder.</jc>
2737    *          builder
2738    *             .staticFileResponseHeader(<js>"Cache-Control"</js>, <js>"nocache"</js>);
2739    *             .staticFileResponseHeaders(<js>"My-Header: foo"</js>);
2740    *
2741    *          <jc>// Same, but using property.</jc>
2742    *          builder
2743    *             .addTo(<jsf>REST_staticFileResponseHeaders</jsf>, <js>"Cache-Control"</js>, <js>"nocache"</js>);
2744    *             .addTo(<jsf>REST_staticFileResponseHeaders</jsf>, <js>"My-Header"</js>, <js>"foo"</js>);
2745    *       }
2746    *
2747    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2748    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2749    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2750    *          builder.staticFileResponseHeader(<js>"Cache-Control"</js>, <js>"nocache"</js>);
2751    *       }
2752    *    }
2753    * </p>
2754    *
2755    * <p>
2756    * Note that headers can also be specified per path-mapping via the {@link Rest#staticFiles() @Rest(staticFiles)} annotation.
2757    * <p class='bcode w800'>
2758    *    <ja>@Rest</ja>(
2759    *       staticFiles={
2760    *          <js>"htdocs:docs:{'Cache-Control':'max-age=86400, public'}"</js>
2761    *       }
2762    *    )
2763    * </p>
2764    *
2765    * <ul class='seealso'>
2766    *    <li class='jf'>{@link #REST_staticFiles} for information about statically-served files.
2767    * </ul>
2768    */
2769   public static final String REST_staticFileResponseHeaders = PREFIX + ".staticFileResponseHeaders.omo";
2770
2771   /**
2772    * Configuration property:  Static file mappings.
2773    *
2774    * <h5 class='section'>Property:</h5>
2775    * <ul class='spaced-list'>
2776    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_staticFiles REST_staticFiles}
2777    *    <li><b>Name:</b>  <js>"RestContext.staticFiles.lo"</js>
2778    *    <li><b>Data type:</b>  <c>List&lt;{@link org.apache.juneau.rest.StaticFileMapping}&gt;</c>
2779    *    <li><b>Default:</b>  <jk>null</jk>
2780    *    <li><b>Session property:</b>  <jk>false</jk>
2781    *    <li><b>Annotations:</b>
2782    *       <ul>
2783    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#staticFiles()}
2784    *       </ul>
2785    *    <li><b>Methods:</b>
2786    *       <ul>
2787    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFiles(String)},
2788    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFiles(Class,String)}
2789    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFiles(String,String)}
2790    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFiles(Class,String,String)}
2791    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#staticFiles(StaticFileMapping...)}
2792    *       </ul>
2793    * </ul>
2794    *
2795    * <h5 class='section'>Description:</h5>
2796    * <p>
2797    * Used to define paths and locations of statically-served files such as images or HTML documents
2798    * from the classpath or file system.
2799    *
2800    * <p>
2801    * The format of the value is one of the following:
2802    * <ol class='spaced-list'>
2803    *    <li><js>"path:location"</js>
2804    *    <li><js>"path:location:headers"</js>
2805    * </ol>
2806    *
2807    * <p>
2808    * An example where this class is used is in the {@link Rest#staticFiles} annotation:
2809    * <p class='bcode w800'>
2810    *    <jk>package</jk> com.foo.mypackage;
2811    *
2812    *    <ja>@Rest</ja>(
2813    *       path=<js>"/myresource"</js>,
2814    *       staticFiles={
2815    *          <js>"htdocs:docs"</js>,
2816    *          <js>"styles:styles"</js>
2817    *       }
2818    *    )
2819    *    <jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {...}
2820    * </p>
2821    *
2822    * <p>
2823    * In the example above, given a GET request to the following URL...
2824    * <p class='bcode w800'>
2825    *    /myresource/htdocs/foobar.html
2826    * </p>
2827    * <br>...the servlet will attempt to find the <c>foobar.html</c> file in the following location:
2828    * <ol class='spaced-list'>
2829    *    <li><c>com.foo.mypackage.docs</c> package.
2830    * </ol>
2831    *
2832    * <p>
2833    * The location is interpreted as an absolute path if it starts with <js>'/'</js>.
2834    * <p class='bcode w800'>
2835    *    <ja>@Rest</ja>(
2836    *       staticFiles={
2837    *          <js>"htdocs:/docs"</js>
2838    *       }
2839    *    )
2840    * </p>
2841    * <p>
2842    * In the example above, given a GET request to the following URL...
2843    * <p class='bcode w800'>
2844    *    /myresource/htdocs/foobar.html
2845    * </p>
2846    * <br>...the servlet will attempt to find the <c>foobar.html</c> file in the following location:
2847    * <ol class='spaced-list'>
2848    *    <li><c>docs</c> package (typically under <c>src/main/resources/docs</c> in your workspace).
2849    *    <li><c>[working-dir]/docs</c> directory at runtime.
2850    * </ol>
2851    *
2852    * <p>
2853    * Response headers can be specified for served files by adding a 3rd section that consists of a {@doc SimpleJson} object.
2854    * <p class='bcode w800'>
2855    *    <ja>@Rest</ja>(
2856    *       staticFiles={
2857    *          <js>"htdocs:docs:{'Cache-Control':'max-age=86400, public'}"</js>
2858    *       }
2859    *    )
2860    * </p>
2861    *
2862    * <p>
2863    * The same path can map to multiple locations.  Files are searched in the order
2864    * <p class='bcode w800'>
2865    *    <ja>@Rest</ja>(
2866    *       staticFiles={
2867    *          <jc>// Search in absolute location '/htdocs/folder' before location 'htdocs.package' relative to servlet package.</jc>
2868    *          <js>"htdocs:/htdocs/folder,htdocs:htdocs.package"</js>
2869    *       }
2870    *    )
2871    * </p>
2872    *
2873    * <ul class='seealso'>
2874    *    <li class='jf'>{@link #REST_classpathResourceFinder} for configuring how classpath resources are located and retrieved.
2875    *    <li class='jf'>{@link #REST_mimeTypes} for configuring the media types based on file extension.
2876    *    <li class='jf'>{@link #REST_staticFileResponseHeaders} for configuring response headers on statically served files.
2877    *    <li class='jf'>{@link #REST_useClasspathResourceCaching} for configuring static file caching.
2878    *    <li class='jm'>{@link RestContext#getClasspathResource(String,Locale)} for retrieving static files.
2879    * </ul>
2880    *
2881    * <ul class='notes'>
2882    *    <li>
2883    *       Mappings are cumulative from super classes.
2884    *    <li>
2885    *       Child resources can override mappings made on parent class resources.
2886    *       <br>When both parent and child resources map against the same path, files will be search in the child location
2887    *       and then the parent location.
2888    * </ul>
2889    */
2890   public static final String REST_staticFiles = PREFIX + ".staticFiles.lo";
2891
2892   /**
2893    * Configuration property:  Supported accept media types.
2894    *
2895    * <h5 class='section'>Property:</h5>
2896    * <ul class='spaced-list'>
2897    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_produces REST_produces}
2898    *    <li><b>Name:</b>  <js>"RestContext.produces.ls"</js>
2899    *    <li><b>Data type:</b>  <c>List&lt;String&gt;</c>
2900    *    <li><b>System property:</b>  <c>RestContext.produces</c>
2901    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_PRODUCES</c>
2902    *    <li><b>Default:</b>  empty list
2903    *    <li><b>Session property:</b>  <jk>false</jk>
2904    *    <li><b>Annotations:</b>
2905    *       <ul>
2906    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#produces()}
2907    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#produces()}
2908    *       </ul>
2909    *    <li><b>Methods:</b>
2910    *       <ul>
2911    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#produces(String...)}
2912    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#produces(MediaType...)}
2913    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#producesReplace(String...)}
2914    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#producesReplace(MediaType...)}
2915    *       </ul>
2916    * </ul>
2917    *
2918    * <h5 class='section'>Description:</h5>
2919    * <p>
2920    * Overrides the media types inferred from the serializers that identify what media types can be produced by the resource.
2921    * <br>An example where this might be useful if you have serializers registered that handle media types that you
2922    * don't want exposed in the Swagger documentation.
2923    *
2924    * <h5 class='section'>Example:</h5>
2925    * <p class='bcode w800'>
2926    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
2927    *    <ja>@Rest</ja>(produces={<js>"$C{REST/supportedProduces,application/json}"</js>})
2928    *    <jk>public class</jk> MyResource {
2929    *
2930    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
2931    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
2932    *
2933    *          <jc>// Using method on builder.</jc>
2934    *          builder.produces(<jk>false</jk>, <js>"application/json"</js>)
2935    *
2936    *          <jc>// Same, but using property.</jc>
2937    *          builder.set(<jsf>REST_produces</jsf>, <js>"application/json"</js>);
2938    *       }
2939    *
2940    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
2941    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
2942    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
2943    *          builder.produces(<jk>false</jk>, <js>"application/json"</js>);
2944    *       }
2945    *    }
2946    * </p>
2947    *
2948    * <p>
2949    * This affects the returned values from the following:
2950    * <ul class='javatree'>
2951    *    <li class='jm'>{@link RestContext#getProduces() RestContext.getProduces()}
2952    *    <li class='jm'>{@link RestRequest#getProduces()}
2953    *    <li class='jm'>{@link RestInfoProvider#getSwagger(RestRequest)} - Affects produces field.
2954    * </ul>
2955    */
2956   public static final String REST_produces = PREFIX + ".produces.ls";
2957
2958   /**
2959    * Configuration property:  Properties.
2960    *
2961    * <h5 class='section'>Property:</h5>
2962    * <ul class='spaced-list'>
2963    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_properties REST_properties}
2964    *    <li><b>Name:</b>  <js>"RestContext.properties.sms"</js>
2965    *    <li><b>Data type:</b>  <c>Map&lt;String,String&gt;</c>
2966    *    <li><b>System property:</b>  <c>RestContext.properties</c>
2967    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_PROPERTIES</c>
2968    *    <li><b>Default:</b>  empty map
2969    *    <li><b>Session property:</b>  <jk>false</jk>
2970    *    <li><b>Annotations:</b>
2971    *       <ul>
2972    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#properties()}
2973    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#flags()}
2974    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#properties()}
2975    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#flags()}
2976    *       </ul>
2977    *    <li><b>Methods:</b>
2978    *       <ul>
2979    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#property(String,Object)}
2980    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#properties(Map)}
2981    *       </ul>
2982    * </ul>
2983    *
2984    * <h5 class='section'>Description:</h5>
2985    * <p>
2986    * Shortcut to add properties to the bean contexts of all serializers and parsers on all methods in the class.
2987    *
2988    * <p>
2989    * Any of the properties defined on {@link RestContext} or any of the serializers and parsers can be specified.
2990    *
2991    * <p>
2992    * Property values will be converted to the appropriate type.
2993    *
2994    * <ul class='notes'>
2995    *    <li>
2996    *       Supports {@doc DefaultRestSvlVariables}
2997    *       (e.g. <js>"$L{my.localized.variable}"</js>).
2998    * </ul>
2999    *
3000    * <ul class='seealso'>
3001    *    <li class='jm'>{@link RestContextBuilder#set(String,Object)}
3002    *    <li class='jm'>{@link RestContextBuilder#set(java.util.Map)}
3003    * </ul>
3004    */
3005   public static final String REST_properties = PREFIX + ".properties.sms";
3006
3007   /**
3008    * Configuration property:  Supported content media types.
3009    *
3010    * <h5 class='section'>Property:</h5>
3011    * <ul class='spaced-list'>
3012    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_consumes REST_consumes}
3013    *    <li><b>Name:</b>  <js>"RestContext.consumes.ls"</js>
3014    *    <li><b>Data type:</b>  <c>List&lt;String&gt;</c>
3015    *    <li><b>System property:</b>  <c>RestContext.consumes</c>
3016    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_CONSUMES</c>
3017    *    <li><b>Default:</b>  empty list
3018    *    <li><b>Session property:</b>  <jk>false</jk>
3019    *    <li><b>Annotations:</b>
3020    *       <ul>
3021    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#consumes()}
3022    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.RestMethod#consumes()}
3023    *       </ul>
3024    *    <li><b>Methods:</b>
3025    *       <ul>
3026    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#consumes(String...)}
3027    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#consumes(MediaType...)}
3028    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#consumesReplace(String...)}
3029    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#consumesReplace(MediaType...)}
3030    *       </ul>
3031    * </ul>
3032    *
3033    * <h5 class='section'>Description:</h5>
3034    * <p>
3035    * Overrides the media types inferred from the parsers that identify what media types can be consumed by the resource.
3036    * <br>An example where this might be useful if you have parsers registered that handle media types that you
3037    * don't want exposed in the Swagger documentation.
3038    *
3039    * <h5 class='section'>Example:</h5>
3040    * <p class='bcode w800'>
3041    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
3042    *    <ja>@Rest</ja>(consumes={<js>"$C{REST/supportedConsumes,application/json}"</js>})
3043    *    <jk>public class</jk> MyResource {
3044    *
3045    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
3046    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
3047    *
3048    *          <jc>// Using method on builder.</jc>
3049    *          builder.consumes(<jk>false</jk>, <js>"application/json"</js>)
3050    *
3051    *          <jc>// Same, but using property.</jc>
3052    *          builder.set(<jsf>REST_consumes</jsf>, <js>"application/json"</js>);
3053    *       }
3054    *
3055    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
3056    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
3057    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
3058    *          builder.consumes(<jk>false</jk>, <js>"application/json"</js>);
3059    *       }
3060    *    }
3061    * </p>
3062    *
3063    * <p>
3064    * This affects the returned values from the following:
3065    * <ul class='javatree'>
3066    *    <li class='jm'>{@link RestContext#getConsumes() RestContext.getConsumes()}
3067    *    <li class='jm'>{@link RestRequest#getConsumes()}
3068    *    <li class='jm'>{@link RestInfoProvider#getSwagger(RestRequest)} - Affects consumes field.
3069    * </ul>
3070    */
3071   public static final String REST_consumes = PREFIX + ".consumes.ls";
3072
3073   /**
3074    * Configuration property:  Use classpath resource caching.
3075    *
3076    * <h5 class='section'>Property:</h5>
3077    * <ul class='spaced-list'>
3078    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_useClasspathResourceCaching REST_useClasspathResourceCaching}
3079    *    <li><b>Name:</b>  <js>"RestContext.useClasspathResourceCaching.b"</js>
3080    *    <li><b>Data type:</b>  <jk>boolean</jk>
3081    *    <li><b>System property:</b>  <c>RestContext.useClasspathResourceCaching</c>
3082    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_USECLASSPATHRESOURCECACHING</c>
3083    *    <li><b>Default:</b>  <jk>true</jk>
3084    *    <li><b>Session property:</b>  <jk>false</jk>
3085    *    <li><b>Annotations:</b>
3086    *       <ul>
3087    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#useClasspathResourceCaching()}
3088    *       </ul>
3089    *    <li><b>Methods:</b>
3090    *       <ul>
3091    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#useClasspathResourceCaching(boolean)}
3092    *       </ul>
3093    * </ul>
3094    *
3095    * <h5 class='section'>Description:</h5>
3096    * <p>
3097    * When enabled, resources retrieved via {@link RestContext#getClasspathResource(String, Locale)} (and related
3098    * methods) will be cached in memory to speed subsequent lookups.
3099    *
3100    * <h5 class='section'>Example:</h5>
3101    * <p class='bcode w800'>
3102    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
3103    *    <ja>@Rest</ja>(useClasspathResourceCaching=<js>"$C{REST/useClasspathResourceCaching,false}"</js>)
3104    *    <jk>public class</jk> MyResource {
3105    *
3106    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
3107    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
3108    *
3109    *          <jc>// Using method on builder.</jc>
3110    *          builder.useClasspathResourceCaching(<jk>false</jk>)
3111    *
3112    *          <jc>// Same, but using property.</jc>
3113    *          builder.set(<jsf>REST_useClasspathResourceCaching</jsf>, <jk>false</jk>);
3114    *       }
3115    *
3116    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
3117    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
3118    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
3119    *          builder.useClasspathResourceCaching(<jk>false</jk>)
3120    *       }
3121    *    }
3122    * </p>
3123    *
3124    * <ul class='seealso'>
3125    *    <li class='jf'>{@link #REST_staticFiles} for information about static files.
3126    * </ul>
3127    */
3128   public static final String REST_useClasspathResourceCaching = PREFIX + ".useClasspathResourceCaching.b";
3129
3130   /**
3131    * Configuration property:  Use stack trace hashes.
3132    *
3133    * <div class='warn'>
3134    *    <b>Deprecated</b> - Use {@link Logging#useStackTraceHashing}
3135    * </div>
3136    */
3137   @Deprecated
3138   public static final String REST_useStackTraceHashes = PREFIX + ".useStackTraceHashes.b";
3139
3140   /**
3141    * Configuration property:  Resource URI authority path.
3142    *
3143    * <h5 class='section'>Property:</h5>
3144    * <ul class='spaced-list'>
3145    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_uriAuthority REST_uriAuthority}
3146    *    <li><b>Name:</b>  <js>"RestContext.uriAuthority.s"</js>
3147    *    <li><b>Data type:</b>  <c>String</c>
3148    *    <li><b>System property:</b>  <c>RestContext.uriAuthority</c>
3149    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_URIAUTHORITY</c>
3150    *    <li><b>Default:</b>  <jk>null</jk>
3151    *    <li><b>Session property:</b>  <jk>false</jk>
3152    *    <li><b>Annotations:</b>
3153    *       <ul>
3154    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#uriAuthority()}
3155    *       </ul>
3156    *    <li><b>Methods:</b>
3157    *       <ul>
3158    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#uriAuthority(String)}
3159    *       </ul>
3160    * </ul>
3161    *
3162    * <h5 class='section'>Description:</h5>
3163    * <p>
3164    * Overrides the authority path value for this resource and any child resources.
3165    *
3166    * <p>
3167    * Affects the following methods:
3168    * <ul class='javatree'>
3169    *    <li class='jm'>{@link RestRequest#getAuthorityPath()}
3170    * </ul>
3171    *
3172    * <p>
3173    * If you do not specify the authority, it is automatically calculated via the following:
3174    *
3175    * <p class='bcode w800'>
3176    *    String scheme = request.getScheme();
3177    *    <jk>int</jk> port = request.getServerPort();
3178    *    StringBuilder sb = <jk>new</jk> StringBuilder(request.getScheme()).append(<js>"://"</js>).append(request.getServerName());
3179    *    <jk>if</jk> (! (port == 80 &amp;&amp; <js>"http"</js>.equals(scheme) || port == 443 &amp;&amp; <js>"https"</js>.equals(scheme)))
3180    *       sb.append(<js>':'</js>).append(port);
3181    *    authorityPath = sb.toString();
3182    * </p>
3183    *
3184    * <h5 class='section'>Example:</h5>
3185    * <p class='bcode w800'>
3186    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
3187    *    <ja>@Rest</ja>(
3188    *       path=<js>"/servlet"</js>,
3189    *       uriAuthority=<js>"$C{REST/authorityPathOverride,http://localhost:10000}"</js>
3190    *    )
3191    *    <jk>public class</jk> MyResource {
3192    *
3193    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
3194    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
3195    *
3196    *          <jc>// Using method on builder.</jc>
3197    *          builder.uriAuthority(<js>"http://localhost:10000"</js>);
3198    *
3199    *          <jc>// Same, but using property.</jc>
3200    *          builder.set(<jsf>REST_uriAuthority</jsf>, <js>"http://localhost:10000"</js>);
3201    *       }
3202    *
3203    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
3204    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
3205    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
3206    *          builder.uriAuthority(<js>"http://localhost:10000"</js>);
3207    *       }
3208    *    }
3209    * </p>
3210    */
3211   public static final String REST_uriAuthority = PREFIX + ".uriAuthority.s";
3212
3213   /**
3214    * Configuration property:  Resource URI context path.
3215    *
3216    * <h5 class='section'>Property:</h5>
3217    * <ul class='spaced-list'>
3218    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_uriContext REST_uriContext}
3219    *    <li><b>Name:</b>  <js>"RestContext.uriContext.s"</js>
3220    *    <li><b>Data type:</b>  <c>String</c>
3221    *    <li><b>System property:</b>  <c>RestContext.uriContext</c>
3222    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_URICONTEXT</c>
3223    *    <li><b>Default:</b>  <jk>null</jk>
3224    *    <li><b>Session property:</b>  <jk>false</jk>
3225    *    <li><b>Annotations:</b>
3226    *       <ul>
3227    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#uriContext()}
3228    *       </ul>
3229    *    <li><b>Methods:</b>
3230    *       <ul>
3231    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#uriContext(String)}
3232    *       </ul>
3233    * </ul>
3234    *
3235    * <h5 class='section'>Description:</h5>
3236    * <p>
3237    * Overrides the context path value for this resource and any child resources.
3238    *
3239    * <p>
3240    * This setting is useful if you want to use <js>"context:/child/path"</js> URLs in child resource POJOs but
3241    * the context path is not actually specified on the servlet container.
3242    *
3243    * <p>
3244    * Affects the following methods:
3245    * <ul class='javatree'>
3246    *    <li class='jm'>{@link RestRequest#getContextPath()} - Returns the overridden context path for the resource.
3247    *    <li class='jm'>{@link RestRequest#getServletPath()} - Includes the overridden context path for the resource.
3248    * </ul>
3249    *
3250    * <h5 class='section'>Example:</h5>
3251    * <p class='bcode w800'>
3252    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
3253    *    <ja>@Rest</ja>(
3254    *       path=<js>"/servlet"</js>,
3255    *       uriContext=<js>"$C{REST/contextPathOverride,/foo}"</js>
3256    *    )
3257    *    <jk>public class</jk> MyResource {
3258    *
3259    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
3260    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
3261    *
3262    *          <jc>// Using method on builder.</jc>
3263    *          builder.uriContext(<js>"/foo"</js>);
3264    *
3265    *          <jc>// Same, but using property.</jc>
3266    *          builder.set(<jsf>REST_uriContext</jsf>, <js>"/foo"</js>);
3267    *       }
3268    *
3269    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
3270    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
3271    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
3272    *          builder.uriContext(<js>"/foo"</js>);
3273    *       }
3274    *    }
3275    * </p>
3276    */
3277   public static final String REST_uriContext = PREFIX + ".uriContext.s";
3278
3279   /**
3280    * Configuration property:  URI resolution relativity.
3281    *
3282    * <h5 class='section'>Property:</h5>
3283    * <ul class='spaced-list'>
3284    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_uriRelativity REST_uriRelativity}
3285    *    <li><b>Name:</b>  <js>"RestContext.uriRelativity.s"</js>
3286    *    <li><b>Data type:</b>  <c>String</c>
3287    *    <li><b>System property:</b>  <c>RestContext.uriRelativity</c>
3288    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_URIRELATIVITY</c>
3289    *    <li><b>Default:</b>  <js>"RESOURCE"</js>
3290    *    <li><b>Session property:</b>  <jk>false</jk>
3291    *    <li><b>Annotations:</b>
3292    *       <ul>
3293    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#uriRelativity()}
3294    *       </ul>
3295    *    <li><b>Methods:</b>
3296    *       <ul>
3297    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#uriRelativity(String)}
3298    *       </ul>
3299    * </ul>
3300    *
3301    * <h5 class='section'>Description:</h5>
3302    * <p>
3303    * Specifies how relative URIs should be interpreted by serializers.
3304    *
3305    * <p>
3306    * See {@link UriResolution} for possible values.
3307    *
3308    * <p>
3309    * Affects the following methods:
3310    * <ul class='javatree'>
3311    *    <li class='jm'>{@link RestRequest#getUriResolver()}
3312    * </ul>
3313    *
3314    * <h5 class='section'>Example:</h5>
3315    * <p class='bcode w800'>
3316    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
3317    *    <ja>@Rest</ja>(
3318    *       path=<js>"/servlet"</js>,
3319    *       uriRelativity=<js>"$C{REST/uriRelativity,PATH_INFO}"</js>
3320    *    )
3321    *    <jk>public class</jk> MyResource {
3322    *
3323    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
3324    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
3325    *
3326    *          <jc>// Using method on builder.</jc>
3327    *          builder.uriRelativity(<js>"PATH_INFO"</js>);
3328    *
3329    *          <jc>// Same, but using property.</jc>
3330    *          builder.set(<jsf>REST_uriRelativity</jsf>, <js>"PATH_INFO"</js>);
3331    *       }
3332    *
3333    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
3334    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
3335    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
3336    *          builder.uriRelativity(<js>"PATH_INFO"</js>);
3337    *       }
3338    *    }
3339    * </p>
3340    */
3341   public static final String REST_uriRelativity = PREFIX + ".uriRelativity.s";
3342
3343   /**
3344    * Configuration property:  URI resolution.
3345    *
3346    * <h5 class='section'>Property:</h5>
3347    * <ul class='spaced-list'>
3348    *    <li><b>ID:</b>  {@link org.apache.juneau.rest.RestContext#REST_uriResolution REST_uriResolution}
3349    *    <li><b>Name:</b>  <js>"RestContext.uriResolution.s"</js>
3350    *    <li><b>Data type:</b>  <c>String</c>
3351    *    <li><b>System property:</b>  <c>RestContext.uriResolution</c>
3352    *    <li><b>Environment variable:</b>  <c>RESTCONTEXT_URIRESOLUTION</c>
3353    *    <li><b>Default:</b>  <js>"ROOT_RELATIVE"</js>
3354    *    <li><b>Session property:</b>  <jk>false</jk>
3355    *    <li><b>Annotations:</b>
3356    *       <ul>
3357    *          <li class='ja'>{@link org.apache.juneau.rest.annotation.Rest#uriResolution()}
3358    *       </ul>
3359    *    <li><b>Methods:</b>
3360    *       <ul>
3361    *          <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#uriResolution(String)}
3362    *       </ul>
3363    * </ul>
3364    *
3365    * <h5 class='section'>Description:</h5>
3366    * <p>
3367    * Specifies how relative URIs should be interpreted by serializers.
3368    *
3369    * <p>
3370    * See {@link UriResolution} for possible values.
3371    *
3372    * <p>
3373    * Affects the following methods:
3374    * <ul class='javatree'>
3375    *    <li class='jm'>{@link RestRequest#getUriResolver()}
3376    * </ul>
3377    *
3378    * <h5 class='section'>Example:</h5>
3379    * <p class='bcode w800'>
3380    *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
3381    *    <ja>@Rest</ja>(
3382    *       path=<js>"/servlet"</js>,
3383    *       uriResolution=<js>"$C{REST/uriResolution,ABSOLUTE}"</js>
3384    *    )
3385    *    <jk>public class</jk> MyResource {
3386    *
3387    *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
3388    *       <jk>public</jk> MyResource(RestContextBuilder builder) <jk>throws</jk> Exception {
3389    *
3390    *          <jc>// Using method on builder.</jc>
3391    *          builder.uriResolution(<js>"ABSOLUTE"</js>);
3392    *
3393    *          <jc>// Same, but using property.</jc>
3394    *          builder.set(<jsf>REST_uriResolution</jsf>, <js>"ABSOLUTE"</js>);
3395    *       }
3396    *
3397    *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
3398    *       <ja>@RestHook</ja>(<jsf>INIT</jsf>)
3399    *       <jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
3400    *          builder.uriResolution(<js>"ABSOLUTE"</js>);
3401    *       }
3402    *    }
3403    * </p>
3404    */
3405   public static final String REST_uriResolution = PREFIX + ".uriResolution.s";
3406
3407   /**
3408    * Configuration property:  HTML Widgets.
3409    *
3410    * <div class='warn'>
3411    *    <b>Deprecated</b> - Use {@link HtmlDocSerializer#HTMLDOC_widgets}
3412    * </div>
3413    */
3414   @Deprecated
3415   public static final String REST_widgets = PREFIX + ".widgets.lo";
3416
3417
3418   //-------------------------------------------------------------------------------------------------------------------
3419   // Instance
3420   //-------------------------------------------------------------------------------------------------------------------
3421
3422   private final Object resource;
3423   final RestContextBuilder builder;
3424   private final boolean
3425      allowBodyParam,
3426      renderResponseStackTraces,
3427      useClasspathResourceCaching;
3428   private final Enablement debug;
3429   @Deprecated private final boolean
3430      useStackTraceHashes;
3431   private final String
3432      clientVersionHeader,
3433      uriAuthority,
3434      uriContext;
3435   final String fullPath;
3436   final UrlPathPattern pathPattern;
3437
3438   private final Set<String> allowedMethodParams, allowedHeaderParams, allowedMethodHeaders;
3439
3440   private final RestContextProperties properties;
3441   private final Map<Class<?>,RestMethodParam> paramResolvers;
3442   private final SerializerGroup serializers;
3443   private final ParserGroup parsers;
3444   private final HttpPartSerializer partSerializer;
3445   private final HttpPartParser partParser;
3446   private final JsonSchemaGenerator jsonSchemaGenerator;
3447   private final List<MediaType>
3448      consumes,
3449      produces;
3450   private final Map<String,Object>
3451      reqHeaders,
3452      resHeaders,
3453      staticFileResponseHeaders;
3454   private final ObjectMap reqAttrs;
3455   private final ResponseHandler[] responseHandlers;
3456   private final MimetypesFileTypeMap mimetypesFileTypeMap;
3457   private final StaticFiles[] staticFiles;
3458   private final String[] staticFilesPaths;
3459   private final MessageBundle msgs;
3460   private final Config config;
3461   private final VarResolver varResolver;
3462   private final Map<String,RestCallRouter> callRouters;
3463   private final Map<String,RestMethodContext> callMethods;
3464   private final Map<String,RestContext> childResources;
3465   @SuppressWarnings("deprecation") private final RestLogger logger;
3466   private final RestCallLogger callLogger;
3467   private final RestCallLoggerConfig callLoggerConfig;
3468   private final StackTraceDatabase stackTraceDb;
3469   private final RestCallHandler callHandler;
3470   private final RestInfoProvider infoProvider;
3471   private final HttpException initException;
3472   private final RestContext parentContext;
3473   private final RestResourceResolver resourceResolver;
3474   private final UriResolution uriResolution;
3475   private final UriRelativity uriRelativity;
3476   private final ConcurrentHashMap<String,MethodExecStats> methodExecStats = new ConcurrentHashMap<>();
3477   private final Instant startTime;
3478
3479   // Lifecycle methods
3480   private final MethodInvoker[]
3481      postInitMethods,
3482      postInitChildFirstMethods,
3483      preCallMethods,
3484      postCallMethods,
3485      startCallMethods,
3486      endCallMethods,
3487      destroyMethods;
3488   private final RestMethodParam[][]
3489      preCallMethodParams,
3490      postCallMethodParams;
3491   private final Class<?>[][]
3492      postInitMethodParams,
3493      postInitChildFirstMethodParams,
3494      startCallMethodParams,
3495      endCallMethodParams,
3496      destroyMethodParams;
3497
3498   // In-memory cache of images and stylesheets in the org.apache.juneau.rest.htdocs package.
3499   private final Map<String,StaticFile> staticFilesCache = new ConcurrentHashMap<>();
3500
3501   private final ClasspathResourceManager staticResourceManager;
3502   @Deprecated private final ConcurrentHashMap<Integer,AtomicInteger> stackTraceHashes = new ConcurrentHashMap<>();
3503
3504   private final ThreadLocal<RestRequest> req = new ThreadLocal<>();
3505   private final ThreadLocal<RestResponse> res = new ThreadLocal<>();
3506
3507   /**
3508    * Constructor.
3509    *
3510    * @param resource The resource annotated with <ja>@Rest</ja>.
3511    * @return A new builder object.
3512    * @throws ServletException Something bad happened.
3513    */
3514   public static RestContextBuilder create(Object resource) throws ServletException {
3515      return new RestContextBuilder(null, resource.getClass(), null).init(resource);
3516   }
3517
3518   /**
3519    * Constructor.
3520    *
3521    * @param servletConfig The servlet config passed into the servlet by the servlet container.
3522    * @param resourceClass The class annotated with <ja>@Rest</ja>.
3523    * @param parentContext The parent context, or <jk>null</jk> if there is no parent context.
3524    * @return A new builder object.
3525    * @throws ServletException Something bad happened.
3526    */
3527   static RestContextBuilder create(ServletConfig servletConfig, Class<?> resourceClass, RestContext parentContext) throws ServletException {
3528      return new RestContextBuilder(servletConfig, resourceClass, parentContext);
3529   }
3530
3531   /**
3532    * Constructor.
3533    *
3534    * @param builder The servlet configuration object.
3535    * @throws Exception If any initialization problems were encountered.
3536    */
3537   @SuppressWarnings("deprecation")
3538   RestContext(RestContextBuilder builder) throws Exception {
3539      super(builder.getPropertyStore());
3540
3541      startTime = Instant.now();
3542
3543      HttpException _initException = null;
3544
3545      try {
3546         ServletContext servletContext = builder.servletContext;
3547
3548         this.resource = builder.resource;
3549         this.builder = builder;
3550         this.parentContext = builder.parentContext;
3551         resourceResolver = getInstanceProperty(REST_resourceResolver, resource, RestResourceResolver.class, parentContext == null ? BasicRestResourceResolver.class : parentContext.resourceResolver, ResourceResolver.FUZZY, this);
3552
3553         varResolver = builder.varResolverBuilder
3554            .vars(
3555               FileVar.class,
3556               LocalizationVar.class,
3557               RequestAttributeVar.class,
3558               RequestFormDataVar.class,
3559               RequestHeaderVar.class,
3560               RequestPathVar.class,
3561               RequestQueryVar.class,
3562               RequestVar.class,
3563               RestInfoVar.class,
3564               SerializedRequestAttrVar.class,
3565               ServletInitParamVar.class,
3566               SwaggerVar.class,
3567               UrlVar.class,
3568               UrlEncodeVar.class,
3569               WidgetVar.class
3570            )
3571            .build()
3572         ;
3573
3574         VarResolverSession vrs = this.varResolver.createSession();
3575         config = builder.config.resolving(vrs);
3576
3577         ClassInfo rci = ClassInfo.of(resource);
3578
3579         PropertyStore ps = getPropertyStore();
3580
3581         uriContext = nullIfEmpty(getStringProperty(REST_uriContext, null));
3582         uriAuthority = nullIfEmpty(getStringProperty(REST_uriAuthority, null));
3583         uriResolution = getProperty(REST_uriResolution, UriResolution.class, UriResolution.ROOT_RELATIVE);
3584         uriRelativity = getProperty(REST_uriRelativity, UriRelativity.class, UriRelativity.RESOURCE);
3585
3586         allowBodyParam = getBooleanProperty(REST_allowBodyParam, true);
3587         allowedHeaderParams = newUnmodifiableSortedCaseInsensitiveSet(getStringPropertyWithNone(REST_allowedHeaderParams, "Accept,Content-Type"));
3588         allowedMethodParams = newUnmodifiableSortedCaseInsensitiveSet(getStringPropertyWithNone(REST_allowedMethodParams, "HEAD,OPTIONS"));
3589         allowedMethodHeaders = newUnmodifiableSortedCaseInsensitiveSet(getStringPropertyWithNone(REST_allowedMethodHeaders, ""));
3590         renderResponseStackTraces = getBooleanProperty(REST_renderResponseStackTraces, false);
3591         useStackTraceHashes = getBooleanProperty(REST_useStackTraceHashes, true);
3592         debug = getInstanceProperty(REST_debug, Enablement.class, Enablement.FALSE);
3593         clientVersionHeader = getStringProperty(REST_clientVersionHeader, "X-Client-Version");
3594
3595         responseHandlers = getInstanceArrayProperty(REST_responseHandlers, resource, ResponseHandler.class, new ResponseHandler[0], resourceResolver, this);
3596
3597         Map<Class<?>,RestMethodParam> _paramResolvers = new HashMap<>();
3598         for (RestMethodParam rp : getInstanceArrayProperty(REST_paramResolvers, RestMethodParam.class, new RestMethodParam[0], resourceResolver, this))
3599            _paramResolvers.put(rp.forClass(), rp);
3600         paramResolvers = unmodifiableMap(_paramResolvers);
3601
3602         Map<String,Object> _reqHeaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
3603         _reqHeaders.putAll(getMapProperty(REST_reqHeaders, String.class));
3604         reqHeaders = unmodifiableMap(new LinkedHashMap<>(_reqHeaders));
3605
3606         reqAttrs = new ObjectMap(getMapProperty(REST_reqAttrs, Object.class)).unmodifiable();
3607         resHeaders = getMapProperty(REST_resHeaders, Object.class);
3608         staticFileResponseHeaders = getMapProperty(REST_staticFileResponseHeaders, Object.class);
3609
3610         logger = getInstanceProperty(REST_logger, resource, RestLogger.class, NoOpRestLogger.class, resourceResolver, this);
3611
3612         if (debug == Enablement.TRUE) {
3613            this.callLoggerConfig = RestCallLoggerConfig.DEFAULT_DEBUG;
3614         } else {
3615            Object clc = getProperty(REST_callLoggerConfig);
3616            if (clc instanceof RestCallLoggerConfig)
3617               this.callLoggerConfig = (RestCallLoggerConfig)clc;
3618            else if (clc instanceof ObjectMap)
3619               this.callLoggerConfig = RestCallLoggerConfig.create().apply((ObjectMap)clc).build();
3620            else
3621               this.callLoggerConfig = RestCallLoggerConfig.DEFAULT;
3622         }
3623
3624         this.stackTraceDb = new StackTraceDatabase(callLoggerConfig.getStackTraceHashingTimeout(), RestMethodContext.class);
3625
3626         callLogger = getInstanceProperty(REST_callLogger, resource, RestCallLogger.class, BasicRestCallLogger.class, resourceResolver, this);
3627
3628         properties = builder.properties;
3629         serializers =
3630            SerializerGroup
3631            .create()
3632            .append(getInstanceArrayProperty(REST_serializers, Serializer.class, new Serializer[0], resourceResolver, resource, ps))
3633            .build();
3634         parsers =
3635            ParserGroup
3636            .create()
3637            .append(getInstanceArrayProperty(REST_parsers, Parser.class, new Parser[0], resourceResolver, resource, ps))
3638            .build();
3639         partSerializer =
3640            (HttpPartSerializer)
3641            SerializerGroup
3642            .create()
3643            .append(getInstanceProperty(REST_partSerializer, HttpPartSerializer.class, OpenApiSerializer.class, resourceResolver, resource, ps))
3644            .build()
3645            .getSerializers()
3646            .get(0);
3647         partParser =
3648            (HttpPartParser)
3649            ParserGroup
3650            .create()
3651            .append(getInstanceProperty(REST_partParser, HttpPartParser.class, OpenApiParser.class, resourceResolver, resource, ps))
3652            .build()
3653            .getParsers()
3654            .get(0);
3655         jsonSchemaGenerator =
3656            JsonSchemaGenerator
3657            .create()
3658            .apply(ps)
3659            .build();
3660
3661         mimetypesFileTypeMap = new ExtendedMimetypesFileTypeMap();
3662         for (String mimeType : getArrayProperty(REST_mimeTypes, String.class))
3663            mimetypesFileTypeMap.addMimeTypes(mimeType);
3664
3665         ClasspathResourceFinder rf = getInstanceProperty(REST_classpathResourceFinder, ClasspathResourceFinder.class, ClasspathResourceFinderBasic.class, resourceResolver, this);
3666         useClasspathResourceCaching = getProperty(REST_useClasspathResourceCaching, boolean.class, true);
3667         staticResourceManager = new ClasspathResourceManager(rci.getProxiedClass(), rf, useClasspathResourceCaching);
3668
3669         consumes = getListProperty(REST_consumes, MediaType.class, parsers.getSupportedMediaTypes());
3670         produces = getListProperty(REST_produces, MediaType.class, serializers.getSupportedMediaTypes());
3671
3672         StaticFileMapping[] staticFileMappings = getArrayProperty(REST_staticFiles, StaticFileMapping.class, new StaticFileMapping[0]);
3673         staticFiles = new StaticFiles[staticFileMappings.length];
3674         for (int i = 0; i < staticFiles.length; i++)
3675            staticFiles[i] = new StaticFiles(staticFileMappings[i], staticResourceManager, mimetypesFileTypeMap, staticFileResponseHeaders);
3676
3677         Set<String> s = new TreeSet<>();
3678         for (StaticFiles sf : staticFiles)
3679            s.add(sf.getPath());
3680         staticFilesPaths = s.toArray(new String[s.size()]);
3681
3682         MessageBundleLocation[] mbl = getInstanceArrayProperty(REST_messages, MessageBundleLocation.class, new MessageBundleLocation[0]);
3683         if (mbl.length == 0)
3684            msgs = new MessageBundle(rci.getProxiedClass(), "");
3685         else {
3686            msgs = new MessageBundle(mbl[0] != null ? mbl[0].baseClass : rci.getProxiedClass(), mbl[0].bundlePath);
3687            for (int i = 1; i < mbl.length; i++)
3688               msgs.addSearchPath(mbl[i] != null ? mbl[i].baseClass : rci.getProxiedClass(), mbl[i].bundlePath);
3689         }
3690
3691         this.fullPath = (builder.parentContext == null ? "" : (builder.parentContext.fullPath + '/')) + builder.getPath();
3692
3693         String p = builder.getPath();
3694         if (! p.endsWith("/*"))
3695            p += "/*";
3696         this.pathPattern = new UrlPathPattern(p);
3697
3698         this.childResources = Collections.synchronizedMap(new LinkedHashMap<String,RestContext>());  // Not unmodifiable on purpose so that children can be replaced.
3699
3700         //----------------------------------------------------------------------------------------------------
3701         // Initialize the child resources.
3702         // Done after initializing fields above since we pass this object to the child resources.
3703         //----------------------------------------------------------------------------------------------------
3704         List<String> methodsFound = new LinkedList<>();   // Temporary to help debug transient duplicate method issue.
3705         Map<String,RestCallRouter.Builder> routers = new LinkedHashMap<>();
3706         Map<String,RestMethodContext> _javaRestMethods = new LinkedHashMap<>();
3707         Map<String,Method>
3708            _startCallMethods = new LinkedHashMap<>(),
3709            _preCallMethods = new LinkedHashMap<>(),
3710            _postCallMethods = new LinkedHashMap<>(),
3711            _endCallMethods = new LinkedHashMap<>(),
3712            _postInitMethods = new LinkedHashMap<>(),
3713            _postInitChildFirstMethods = new LinkedHashMap<>(),
3714            _destroyMethods = new LinkedHashMap<>();
3715         List<RestMethodParam[]>
3716            _preCallMethodParams = new ArrayList<>(),
3717            _postCallMethodParams = new ArrayList<>();
3718         List<Class<?>[]>
3719            _startCallMethodParams = new ArrayList<>(),
3720            _endCallMethodParams = new ArrayList<>(),
3721            _postInitMethodParams = new ArrayList<>(),
3722            _postInitChildFirstMethodParams = new ArrayList<>(),
3723            _destroyMethodParams = new ArrayList<>();
3724
3725         for (MethodInfo mi : rci.getPublicMethods()) {
3726            RestMethod a = mi.getAnnotation(RestMethod.class);
3727            if (a != null) {
3728               methodsFound.add(mi.getSimpleName() + "," + emptyIfNull(firstNonEmpty(a.name(), a.method())) + "," + fixMethodPath(a.path()));
3729               try {
3730                  if (mi.isNotPublic())
3731                     throw new RestServletException("@RestMethod method {0}.{1} must be defined as public.", rci.getProxiedClass().getName(), mi.getSimpleName());
3732
3733                  RestMethodContextBuilder rmcb = new RestMethodContextBuilder(resource, mi.inner(), this);
3734                  RestMethodContext sm = new RestMethodContext(rmcb);
3735                  String httpMethod = sm.getHttpMethod();
3736
3737                  // RRPC is a special case where a method returns an interface that we
3738                  // can perform REST calls against.
3739                  // We override the CallMethod.invoke() method to insert our logic.
3740                  if ("RRPC".equals(httpMethod)) {
3741
3742                     final ClassMeta<?> interfaceClass = getClassMeta(mi.inner().getGenericReturnType());
3743                     final RemoteInterfaceMeta rim = new RemoteInterfaceMeta(interfaceClass.getInnerClass(), null);
3744                     if (rim.getMethodsByPath().isEmpty())
3745                        throw new RestException(SC_INTERNAL_SERVER_ERROR, "Method {0} returns an interface {1} that doesn't define any remote methods.", mi.getSignature(), interfaceClass.getFullName());
3746
3747                     RestMethodContextBuilder smb = new RestMethodContextBuilder(resource, mi.inner(), this);
3748                     sm = new RestMethodContext(smb) {
3749
3750                        @Override
3751                        int invoke(RestCall call) throws Throwable {
3752
3753                           int rc = super.invoke(call);
3754                           if (rc != SC_OK)
3755                              return rc;
3756
3757                           final Object o = call.getOutput();
3758
3759                           if ("GET".equals(call.getMethod())) {
3760                              call.output(rim.getMethodsByPath().keySet());
3761                              return SC_OK;
3762
3763                           } else if ("POST".equals(call.getMethod())) {
3764                              String pip = call.getUrlPathInfo().getPath();
3765                              if (pip.indexOf('/') != -1)
3766                                 pip = pip.substring(pip.lastIndexOf('/')+1);
3767                              pip = urlDecode(pip);
3768                              RemoteInterfaceMethod rmm = rim.getMethodMetaByPath(pip);
3769                              if (rmm != null) {
3770                                 Method m = rmm.getJavaMethod();
3771                                 try {
3772                                    RestRequest req = call.getRestRequest();
3773                                    // Parse the args and invoke the method.
3774                                    Parser p = req.getBody().getParser();
3775                                    Object[] args = null;
3776                                    if (m.getGenericParameterTypes().length == 0)
3777                                       args = new Object[0];
3778                                    else {
3779                                       try (Closeable in = p.isReaderParser() ? req.getReader() : req.getInputStream()) {
3780                                          args = p.parseArgs(in, m.getGenericParameterTypes());
3781                                       }
3782                                    }
3783                                    Object output = m.invoke(o, args);
3784                                    call.output(output);
3785                                    return SC_OK;
3786                                 } catch (Exception e) {
3787                                    throw toHttpException(e, InternalServerError.class);
3788                                 }
3789                              }
3790                           }
3791                           return SC_NOT_FOUND;
3792                        }
3793                     };
3794
3795                     _javaRestMethods.put(mi.getSimpleName(), sm);
3796                     addToRouter(routers, "GET", sm);
3797                     addToRouter(routers, "POST", sm);
3798
3799                  } else {
3800                     _javaRestMethods.put(mi.getSimpleName(), sm);
3801                     addToRouter(routers, httpMethod, sm);
3802                  }
3803               } catch (Throwable e) {
3804                  throw new RestServletException("Problem occurred trying to serialize methods on class {0}, methods={1}", rci.getProxiedClass().getName(), SimpleJsonSerializer.DEFAULT.serialize(methodsFound)).initCause(e);
3805               }
3806            }
3807         }
3808
3809         for (MethodInfo m : rci.getAllMethodsParentFirst()) {
3810            if (m.isPublic() && m.hasAnnotation(RestHook.class)) {
3811               HookEvent he = m.getAnnotation(RestHook.class).value();
3812               String sig = m.getSignature();
3813               switch(he) {
3814                  case PRE_CALL: {
3815                     if (! _preCallMethods.containsKey(sig)) {
3816                        m.setAccessible();
3817                        _preCallMethods.put(sig, m.inner());
3818                        _preCallMethodParams.add(findParams(m, true, null));
3819                     }
3820                     break;
3821                  }
3822                  case POST_CALL: {
3823                     if (! _postCallMethods.containsKey(sig)) {
3824                        m.setAccessible();
3825                        _postCallMethods.put(sig, m.inner());
3826                        _postCallMethodParams.add(findParams(m, true, null));
3827                     }
3828                     break;
3829                  }
3830                  case START_CALL: {
3831                     if (! _startCallMethods.containsKey(sig)) {
3832                        m.setAccessible();
3833                        _startCallMethods.put(sig, m.inner());
3834                        _startCallMethodParams.add(m.getRawParamTypes());
3835                        assertArgsOnlyOfType(m, HttpServletRequest.class, HttpServletResponse.class);
3836                     }
3837                     break;
3838                  }
3839                  case END_CALL: {
3840                     if (! _endCallMethods.containsKey(sig)) {
3841                        m.setAccessible();
3842                        _endCallMethods.put(sig, m.inner());
3843                        _endCallMethodParams.add(m.getRawParamTypes());
3844                        assertArgsOnlyOfType(m, HttpServletRequest.class, HttpServletResponse.class);
3845                     }
3846                     break;
3847                  }
3848                  case POST_INIT: {
3849                     if (! _postInitMethods.containsKey(sig)) {
3850                        m.setAccessible();
3851                        _postInitMethods.put(sig, m.inner());
3852                        _postInitMethodParams.add(m.getRawParamTypes());
3853                        assertArgsOnlyOfType(m, RestContext.class);
3854                     }
3855                     break;
3856                  }
3857                  case POST_INIT_CHILD_FIRST: {
3858                     if (! _postInitChildFirstMethods.containsKey(sig)) {
3859                        m.setAccessible();
3860                        _postInitChildFirstMethods.put(sig, m.inner());
3861                        _postInitChildFirstMethodParams.add(m.getRawParamTypes());
3862                        assertArgsOnlyOfType(m, RestContext.class);
3863                     }
3864                     break;
3865                  }
3866                  case DESTROY: {
3867                     if (! _destroyMethods.containsKey(sig)) {
3868                        m.setAccessible();
3869                        _destroyMethods.put(sig, m.inner());
3870                        _destroyMethodParams.add(m.getRawParamTypes());
3871                        assertArgsOnlyOfType(m, RestContext.class);
3872                     }
3873                     break;
3874                  }
3875                  default: // Ignore INIT
3876               }
3877            }
3878         }
3879
3880         this.callMethods = unmodifiableMap(_javaRestMethods);
3881         this.preCallMethods = _preCallMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_preCallMethods.size()]);
3882         this.postCallMethods = _postCallMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_postCallMethods.size()]);
3883         this.startCallMethods = _startCallMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_startCallMethods.size()]);
3884         this.endCallMethods = _endCallMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_endCallMethods.size()]);
3885         this.postInitMethods = _postInitMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_postInitMethods.size()]);
3886         this.postInitChildFirstMethods = _postInitChildFirstMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_postInitChildFirstMethods.size()]);
3887         this.destroyMethods = _destroyMethods.values().stream().map(x->new MethodInvoker(x, getMethodExecStats(x))).collect(Collectors.toList()).toArray(new MethodInvoker[_destroyMethods.size()]);
3888         this.preCallMethodParams = _preCallMethodParams.toArray(new RestMethodParam[_preCallMethodParams.size()][]);
3889         this.postCallMethodParams = _postCallMethodParams.toArray(new RestMethodParam[_postCallMethodParams.size()][]);
3890         this.startCallMethodParams = _startCallMethodParams.toArray(new Class[_startCallMethodParams.size()][]);
3891         this.endCallMethodParams = _endCallMethodParams.toArray(new Class[_endCallMethodParams.size()][]);
3892         this.postInitMethodParams = _postInitMethodParams.toArray(new Class[_postInitMethodParams.size()][]);
3893         this.postInitChildFirstMethodParams = _postInitChildFirstMethodParams.toArray(new Class[_postInitChildFirstMethodParams.size()][]);
3894         this.destroyMethodParams = _destroyMethodParams.toArray(new Class[_destroyMethodParams.size()][]);
3895
3896         Map<String,RestCallRouter> _callRouters = new LinkedHashMap<>();
3897         for (RestCallRouter.Builder crb : routers.values())
3898            _callRouters.put(crb.getHttpMethodName(), crb.build());
3899         this.callRouters = unmodifiableMap(_callRouters);
3900
3901         // Initialize our child resources.
3902         for (Object o : getArrayProperty(REST_children, Object.class)) {
3903            String path = null;
3904            Object r = null;
3905            if (o instanceof RestChild) {
3906               RestChild rc = (RestChild)o;
3907               path = rc.path;
3908               r = rc.resource;
3909            } else if (o instanceof Class<?>) {
3910               Class<?> c = (Class<?>)o;
3911               // Don't allow specifying yourself as a child.  Causes an infinite loop.
3912               if (c == builder.resourceClass)
3913                  continue;
3914               r = c;
3915            } else {
3916               r = o;
3917            }
3918
3919            RestContextBuilder childBuilder = null;
3920
3921            if (o instanceof Class) {
3922               Class<?> oc = (Class<?>)o;
3923               childBuilder = RestContext.create(builder.inner, oc, this);
3924               r = resourceResolver.resolve(resource, oc, childBuilder);
3925            } else {
3926               r = o;
3927               childBuilder = RestContext.create(builder.inner, o.getClass(), this);
3928            }
3929
3930            childBuilder.init(r);
3931            if (r instanceof RestServlet)
3932               ((RestServlet)r).innerInit(childBuilder);
3933            childBuilder.servletContext(servletContext);
3934            RestContext rc2 = childBuilder.build();
3935            if (r instanceof RestServlet)
3936               ((RestServlet)r).setContext(rc2);
3937            path = childBuilder.getPath();
3938            childResources.put(path, rc2);
3939         }
3940
3941         callHandler = getInstanceProperty(REST_callHandler, resource, RestCallHandler.class, BasicRestCallHandler.class, resourceResolver, this);
3942         infoProvider = getInstanceProperty(REST_infoProvider, resource, RestInfoProvider.class, BasicRestInfoProvider.class, resourceResolver, this);
3943
3944      } catch (HttpException e) {
3945         _initException = e;
3946         throw e;
3947      } catch (Exception e) {
3948         _initException = new InternalServerError(e);
3949         throw e;
3950      } finally {
3951         initException = _initException;
3952      }
3953   }
3954
3955   private static void addToRouter(Map<String, RestCallRouter.Builder> routers, String httpMethodName, RestMethodContext cm) {
3956      if (! routers.containsKey(httpMethodName))
3957         routers.put(httpMethodName, new RestCallRouter.Builder(httpMethodName));
3958      routers.get(httpMethodName).add(cm);
3959   }
3960
3961   /**
3962    * Returns the resource resolver associated with this context.
3963    *
3964    * <p>
3965    * The resource resolver is used for instantiating child resource classes.
3966    *
3967    * <ul class='seealso'>
3968    *    <li class='jf'>{@link #REST_resourceResolver}
3969    * </ul>
3970    *
3971    * @return The resource resolver associated with this context.
3972    */
3973   protected RestResourceResolver getResourceResolver() {
3974      return resourceResolver;
3975   }
3976
3977   /**
3978    * Returns the time statistics gatherer for the specified method.
3979    *
3980    * @param m The method to get statistics for.
3981    * @return The cached time-stats object.
3982    */
3983   protected MethodExecStats getMethodExecStats(Method m) {
3984      String n = MethodInfo.of(m).getSimpleName();
3985      MethodExecStats ts = methodExecStats.get(n);
3986      if (ts == null) {
3987         methodExecStats.putIfAbsent(n, new MethodExecStats(m));
3988         ts = methodExecStats.get(n);
3989      }
3990      return ts;
3991   }
3992
3993   /**
3994    * Returns the variable resolver for this servlet.
3995    *
3996    * <p>
3997    * Variable resolvers are used to replace variables in property values.
3998    * They can be nested arbitrarily deep.
3999    * They can also return values that themselves contain other variables.
4000    *
4001    * <h5 class='figure'>Example:</h5>
4002    * <p class='bcode w800'>
4003    *    <ja>@Rest</ja>(
4004    *       messages=<js>"nls/Messages"</js>,
4005    *       properties={
4006    *          <ja>@Property</ja>(name=<js>"title"</js>,value=<js>"$L{title}"</js>),  <jc>// Localized variable in Messages.properties</jc>
4007    *          <ja>@Property</ja>(name=<js>"javaVendor"</js>,value=<js>"$S{java.vendor,Oracle}"</js>),  <jc>// System property with default value</jc>
4008    *          <ja>@Property</ja>(name=<js>"foo"</js>,value=<js>"bar"</js>),
4009    *          <ja>@Property</ja>(name=<js>"bar"</js>,value=<js>"baz"</js>),
4010    *          <ja>@Property</ja>(name=<js>"v1"</js>,value=<js>"$R{foo}"</js>),  <jc>// Request variable.  value="bar"</jc>
4011    *          <ja>@Property</ja>(name=<js>"v1"</js>,value=<js>"$R{foo,bar}"</js>),  <jc>// Request variable.  value="bar"</jc>
4012    *       }
4013    *    )
4014    *    <jk>public class</jk> MyRestResource <jk>extends</jk> BasicRestServlet {
4015    * </p>
4016    *
4017    * <p>
4018    * A typical usage pattern involves using variables inside the {@link HtmlDocConfig @HtmlDocConfig} annotation:
4019    * <p class='bcode w800'>
4020    *    <ja>@RestMethod</ja>(
4021    *       name=<jsf>GET</jsf>, path=<js>"/{name}/*"</js>
4022    *    )
4023    *    <ja>@HtmlDocConfig</ja>(
4024    *       navlinks={
4025    *          <js>"up: $R{requestParentURI}"</js>,
4026    *          <js>"options: servlet:/?method=OPTIONS"</js>,
4027    *          <js>"stats: servlet:/stats"</js>,
4028    *          <js>"editLevel: servlet:/editLevel?logger=$A{attribute.name, OFF}"</js>
4029    *       }
4030    *       header={
4031    *          <js>"&lt;h1&gt;$L{MyLocalizedPageTitle}&lt;/h1&gt;"</js>
4032    *       },
4033    *       aside={
4034    *          <js>"$F{resources/AsideText.html}"</js>
4035    *       }
4036    *    )
4037    *    <jk>public</jk> LoggerEntry getLogger(RestRequest req, <ja>@Path</ja> String name) <jk>throws</jk> Exception {
4038    * </p>
4039    *
4040    * <ul class='seealso'>
4041    *    <li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#vars(Class...)} - For adding custom vars.
4042    *    <li class='link'>{@doc juneau-rest-server.SvlVariables}
4043    *    <li class='link'>{@doc DefaultRestSvlVariables}
4044    * </ul>
4045    *
4046    * @return The var resolver in use by this resource.
4047    */
4048   public VarResolver getVarResolver() {
4049      return varResolver;
4050   }
4051
4052   /**
4053    * Returns the config file associated with this servlet.
4054    *
4055    * <p>
4056    * The config file is identified via one of the following:
4057    * <ul class='javatree'>
4058    *    <li class='ja'>{@link Rest#config()}
4059    *    <li class='jm'>{@link RestContextBuilder#config(Config)}
4060    * </ul>
4061    *
4062    * @return
4063    *    The resolving config file associated with this servlet.
4064    *    <br>Never <jk>null</jk>.
4065    */
4066   public Config getConfig() {
4067      return config;
4068   }
4069
4070   /**
4071    * Resolve a static resource file.
4072    *
4073    * <p>
4074    * The location of static resources are defined via:
4075    * <ul class='javatree'>
4076    *    <li class='jf'>{@link RestContext#REST_staticFiles RestContext.REST_staticFiles}
4077    * </ul>
4078    *
4079    * @param pathInfo The unencoded path info.
4080    * @return The wrapped resource, never <jk>null</jk>.
4081    * @throws NotFound Invalid path.
4082    * @throws IOException Thrown by underlying stream.
4083    */
4084   protected StaticFile resolveStaticFile(String pathInfo) throws NotFound, IOException {
4085      if (! staticFilesCache.containsKey(pathInfo)) {
4086         String p = urlDecode(trimSlashes(pathInfo));
4087         if (p.indexOf("..") != -1)
4088            throw new NotFound("Invalid path");
4089         StreamResource sr = null;
4090         for (StaticFiles sf : staticFiles) {
4091            sr = sf.resolve(p);
4092            if (sr != null)
4093               break;
4094         }
4095         StaticFile sf = new StaticFile(sr);
4096         if (useClasspathResourceCaching) {
4097            if (staticFilesCache.size() > 100)
4098               staticFilesCache.clear();
4099            staticFilesCache.put(pathInfo, sf);
4100         }
4101         return sf;
4102      }
4103      return staticFilesCache.get(pathInfo);
4104   }
4105
4106   /**
4107    * A cached static file instance.
4108    */
4109   class StaticFile {
4110      StreamResource resource;
4111      ResponseBeanMeta meta;
4112
4113      /**
4114       * Constructor.
4115       *
4116       * @param resource The inner resource.
4117       */
4118      StaticFile(StreamResource resource) {
4119         this.resource = resource;
4120         this.meta = resource == null ? null : ResponseBeanMeta.create(resource.getClass(), getPropertyStore());
4121      }
4122   }
4123
4124   /**
4125    * Same as {@link Class#getResourceAsStream(String)} except if it doesn't find the resource on this class, searches
4126    * up the parent hierarchy chain.
4127    *
4128    * <p>
4129    * If the resource cannot be found in the classpath, then an attempt is made to look in the JVM working directory.
4130    *
4131    * <p>
4132    * If the <c>locale</c> is specified, then we look for resources whose name matches that locale.
4133    * <br>For example, if looking for the resource <js>"MyResource.txt"</js> for the Japanese locale, we will look for
4134    * files in the following order:
4135    * <ol>
4136    *    <li><js>"MyResource_ja_JP.txt"</js>
4137    *    <li><js>"MyResource_ja.txt"</js>
4138    *    <li><js>"MyResource.txt"</js>
4139    * </ol>
4140    *
4141    * <h5 class='section'>Example:</h5>
4142    * <p class='bcode w800'>
4143    *    <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc>
4144    * <jc>// from the classpath.</jc>
4145    *    <ja>@RestMethod</ja>(path=<js>"/foo"</js>)
4146    *    <jk>public</jk> Object myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) {
4147    *       <jk>return</jk> getContext().getClasspathResource(file, req.getLocale());
4148    *    }
4149    * </p>
4150    *
4151    * <ul class='seealso'>
4152    *    <li class='jf'>{@link #REST_classpathResourceFinder}
4153    * </ul>
4154    *
4155    * @param name The resource name.
4156    * @param locale
4157    *    Optional locale.
4158    *    <br>If <jk>null</jk>, won't look for localized file names.
4159    * @return An input stream of the resource, or <jk>null</jk> if the resource could not be found.
4160    * @throws IOException Thrown by underlying stream.
4161    */
4162   public InputStream getClasspathResource(String name, Locale locale) throws IOException {
4163      return staticResourceManager.getStream(name, locale);
4164   }
4165
4166   /**
4167    * Same as {@link #getClasspathResource(String, Locale)}, but allows you to override the class used for looking
4168    * up the classpath resource.
4169    *
4170    * <h5 class='section'>Example:</h5>
4171    * <p class='bcode w800'>
4172    *    <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc>
4173    * <jc>// from the classpath.</jc>
4174    *    <ja>@RestMethod</ja>(path=<js>"/foo"</js>)
4175    *    <jk>public</jk> Object myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) {
4176    *       <jk>return</jk> getContext().getClasspathResource(SomeOtherClass.<jk>class</jk>, file, req.getLocale());
4177    *    }
4178    * </p>
4179    *
4180    * <ul class='seealso'>
4181    *    <li class='jf'>{@link #REST_classpathResourceFinder}
4182    * </ul>
4183    *
4184    * @param baseClass
4185    *    Overrides the default class to use for retrieving the classpath resource.
4186    *    <br>If <jk>null</jk>, uses the REST resource class.
4187    * @param name The resource name.
4188    * @param locale
4189    *    Optional locale.
4190    *    <br>If <jk>null</jk>, won't look for localized file names.
4191    * @return An input stream of the resource, or <jk>null</jk> if the resource could not be found.
4192    * @throws IOException Thrown by underlying stream.
4193    */
4194   public InputStream getClasspathResource(Class<?> baseClass, String name, Locale locale) throws IOException {
4195      return staticResourceManager.getStream(baseClass, name, locale);
4196   }
4197
4198   /**
4199    * Reads the input stream from {@link #getClasspathResource(String, Locale)} into a String.
4200    *
4201    * <h5 class='section'>Example:</h5>
4202    * <p class='bcode w800'>
4203    *    <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc>
4204    * <jc>// from the classpath.</jc>
4205    *    <ja>@RestMethod</ja>(path=<js>"/foo"</js>)
4206    *    <jk>public</jk> String myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) {
4207    *       <jk>return</jk> getContext().getClasspathResourceAsString(file, req.getLocale());
4208    *    }
4209    * </p>
4210    *
4211    * <ul class='seealso'>
4212    *    <li class='jf'>{@link #REST_classpathResourceFinder}
4213    * </ul>
4214    *
4215    * @param name The resource name.
4216    * @param locale
4217    *    Optional locale.
4218    *    <br>If <jk>null</jk>, won't look for localized file names.
4219    * @return The contents of the stream as a string, or <jk>null</jk> if the resource could not be found.
4220    * @throws IOException If resource could not be found.
4221    */
4222   public String getClasspathResourceAsString(String name, Locale locale) throws IOException {
4223      return staticResourceManager.getString(name, locale);
4224   }
4225
4226   /**
4227    * Same as {@link #getClasspathResourceAsString(String, Locale)}, but allows you to override the class used for looking
4228    * up the classpath resource.
4229    *
4230    * <h5 class='section'>Example:</h5>
4231    * <p class='bcode w800'>
4232    *    <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc>
4233    * <jc>// from the classpath.</jc>
4234    *    <ja>@RestMethod</ja>(path=<js>"/foo"</js>)
4235    *    <jk>public</jk> String myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) {
4236    *       <jk>return</jk> getContext().getClasspathResourceAsString(SomeOtherClass.<jk>class</jk>, file, req.getLocale());
4237    *    }
4238    * </p>
4239    *
4240    * <ul class='seealso'>
4241    *    <li class='jf'>{@link #REST_classpathResourceFinder}
4242    * </ul>
4243    *
4244    * @param baseClass
4245    *    Overrides the default class to use for retrieving the classpath resource.
4246    *    <br>If <jk>null</jk>, uses the REST resource class.
4247    * @param name The resource name.
4248    * @param locale
4249    *    Optional locale.
4250    *    <br>If <jk>null</jk>, won't look for localized file names.
4251    * @return The contents of the stream as a string, or <jk>null</jk> if the resource could not be found.
4252    * @throws IOException If resource could not be found.
4253    */
4254   public String getClasspathResourceAsString(Class<?> baseClass, String name, Locale locale) throws IOException {
4255      return staticResourceManager.getString(baseClass, name, locale);
4256   }
4257
4258   /**
4259    * Reads the input stream from {@link #getClasspathResource(String, Locale)} and parses it into a POJO using the parser
4260    * matched by the specified media type.
4261    *
4262    * <p>
4263    * Useful if you want to load predefined POJOs from JSON files in your classpath.
4264    *
4265    * <h5 class='section'>Example:</h5>
4266    * <p class='bcode w800'>
4267    *    <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc>
4268    * <jc>// from the classpath parsed as an array of beans.</jc>
4269    *    <ja>@RestMethod</ja>(path=<js>"/foo"</js>)
4270    *    <jk>public</jk> MyBean[] myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) {
4271    *       <jk>return</jk> getContext().getClasspathResource(MyBean[].<jk>class</jk>, <jsf>JSON</jsf>, file, req.getLocale());
4272    *    }
4273    * </p>
4274    *
4275    * <ul class='seealso'>
4276    *    <li class='jf'>{@link #REST_classpathResourceFinder}
4277    * </ul>
4278    *
4279    * @param c The class type of the POJO to create.
4280    * @param mediaType The media type of the data in the stream (e.g. <js>"text/json"</js>)
4281    * @param name The resource name (e.g. "htdocs/styles.css").
4282    * @param locale
4283    *    Optional locale.
4284    *    <br>If <jk>null</jk>, won't look for localized file names.
4285    * @return The parsed resource, or <jk>null</jk> if the resource could not be found.
4286    * @throws IOException Thrown by underlying stream.
4287    * @throws ServletException If the media type was unknown or the input could not be parsed into a POJO.
4288    */
4289   public <T> T getClasspathResource(Class<T> c, MediaType mediaType, String name, Locale locale) throws IOException, ServletException {
4290      return getClasspathResource(null, c, mediaType, name, locale);
4291   }
4292
4293   /**
4294    * Same as {@link #getClasspathResource(Class, MediaType, String, Locale)}, except overrides the class used
4295    * for retrieving the classpath resource.
4296    *
4297    * <ul class='seealso'>
4298    *    <li class='jf'>{@link #REST_classpathResourceFinder}
4299    * </ul>
4300    *
4301    * <h5 class='section'>Example:</h5>
4302    * <p class='bcode w800'>
4303    *    <jc>// A rest method that (unsafely!) returns the contents of a localized file </jc>
4304    * <jc>// from the classpath parsed as an array of beans.</jc>
4305    *    <ja>@RestMethod</ja>(path=<js>"/foo"</js>)
4306    *    <jk>public</jk> MyBean[] myMethod(RestRequest req, <ja>@Query</ja>(<js>"file"</js>) String file) {
4307    *       <jk>return</jk> getContext().getClasspathResource(SomeOtherClass.<jk>class</jk>, MyBean[].<jk>class</jk>, <jsf>JSON</jsf>, file, req.getLocale());
4308    *    }
4309    * </p>
4310    *
4311    * @param baseClass
4312    *    Overrides the default class to use for retrieving the classpath resource.
4313    *    <br>If <jk>null</jk>, uses the REST resource class.
4314    * @param c The class type of the POJO to create.
4315    * @param mediaType The media type of the data in the stream (e.g. <js>"text/json"</js>)
4316    * @param name The resource name (e.g. "htdocs/styles.css").
4317    * @param locale
4318    *    Optional locale.
4319    *    <br>If <jk>null</jk>, won't look for localized file names.
4320    * @return The parsed resource, or <jk>null</jk> if the resource could not be found.
4321    * @throws IOException Thrown by underlying stream.
4322    * @throws ServletException If the media type was unknown or the input could not be parsed into a POJO.
4323    */
4324   public <T> T getClasspathResource(Class<?> baseClass, Class<T> c, MediaType mediaType, String name, Locale locale) throws IOException, ServletException {
4325      InputStream is = getClasspathResource(baseClass, name, locale);
4326      if (is == null)
4327         return null;
4328      try {
4329         Parser p = parsers.getParser(mediaType);
4330         if (p == null) {
4331            if (mediaType == MediaType.JSON)
4332               p = JsonParser.DEFAULT;
4333            if (mediaType == MediaType.XML)
4334               p = XmlParser.DEFAULT;
4335            if (mediaType == MediaType.HTML)
4336               p = HtmlParser.DEFAULT;
4337            if (mediaType == MediaType.UON)
4338               p = UonParser.DEFAULT;
4339            if (mediaType == MediaType.URLENCODING)
4340               p = UrlEncodingParser.DEFAULT;
4341            if (mediaType == MediaType.MSGPACK)
4342               p = MsgPackParser.DEFAULT;
4343         }
4344         if (p != null) {
4345            try {
4346               try (Closeable in = p.isReaderParser() ? new InputStreamReader(is, UTF8) : is) {
4347                  return p.parse(in, c);
4348               }
4349            } catch (ParseException e) {
4350               throw new ServletException("Could not parse resource '"+name+" as media type '"+mediaType+"'.", e);
4351            }
4352         }
4353         throw new ServletException("Unknown media type '"+mediaType+"'");
4354      } catch (Exception e) {
4355         throw new ServletException("Could not parse resource with name '"+name+"'", e);
4356      }
4357   }
4358
4359   /**
4360    * Returns the path for this resource as defined by the {@link Rest#path() @Rest(path)} annotation or
4361    * {@link RestContextBuilder#path(String)} method concatenated with those on all parent classes.
4362    *
4363    * <p>
4364    * If path is not specified, returns <js>""</js>.
4365    *
4366    * <ul class='seealso'>
4367    *    <li class='jf'>{@link #REST_path}
4368    * </ul>
4369    *
4370    * @return The servlet path.
4371    */
4372   public String getPath() {
4373      return fullPath;
4374   }
4375
4376   /**
4377    * Returns the logger to use for this resource.
4378    *
4379    * <div class='warn'>
4380    *    <b>Deprecated</b> - Use {@link #getCallLogger()}
4381    * </div>
4382    *
4383    * <ul class='seealso'>
4384    *    <li class='jf'>{@link #REST_logger}
4385    * </ul>
4386    *
4387    * @return
4388    *    The logger to use for this resource.
4389    *    <br>Never <jk>null</jk>.
4390    */
4391   @Deprecated
4392   public RestLogger getLogger() {
4393      return logger;
4394   }
4395
4396   /**
4397    * Returns the call logger to use for this resource.
4398    *
4399    * <ul class='seealso'>
4400    *    <li class='jf'>{@link #REST_callLogger}
4401    * </ul>
4402    *
4403    * @return
4404    *    The call logger to use for this resource.
4405    *    <br>Never <jk>null</jk>.
4406    */
4407   public RestCallLogger getCallLogger() {
4408      return callLogger;
4409   }
4410
4411   /**
4412    * Returns the call logger config to use for this resource.
4413    *
4414    * <ul class='seealso'>
4415    *    <li class='jf'>{@link #REST_callLoggerConfig}
4416    * </ul>
4417    *
4418    * @return
4419    *    The call logger config to use for this resource.
4420    *    <br>Never <jk>null</jk>.
4421    */
4422   public RestCallLoggerConfig getCallLoggerConfig() {
4423      return callLoggerConfig;
4424   }
4425
4426   /**
4427    * Returns the resource bundle used by this resource.
4428    *
4429    * <ul class='seealso'>
4430    *    <li class='jf'>{@link #REST_messages}
4431    * </ul>
4432    *
4433    * @return
4434    *    The resource bundle for this resource.
4435    *    <br>Never <jk>null</jk>.
4436    */
4437   public MessageBundle getMessages() {
4438      return msgs;
4439   }
4440
4441   /**
4442    * Returns the REST information provider used by this resource.
4443    *
4444    * <ul class='seealso'>
4445    *    <li class='jf'>{@link RestContext#REST_infoProvider}
4446    * </ul>
4447    *
4448    * @return
4449    *    The information provider for this resource.
4450    *    <br>Never <jk>null</jk>.
4451    */
4452   public RestInfoProvider getInfoProvider() {
4453      return infoProvider;
4454   }
4455
4456   /**
4457    * Returns the REST call handler used by this resource.
4458    *
4459    * <ul class='seealso'>
4460    *    <li class='jf'>{@link RestContext#REST_callHandler}
4461    * </ul>
4462    *
4463    * @return
4464    *    The call handler for this resource.
4465    *    <br>Never <jk>null</jk>.
4466    */
4467   public RestCallHandler getCallHandler() {
4468      return callHandler;
4469   }
4470
4471   /**
4472    * Returns a map of HTTP method names to call routers.
4473    *
4474    * @return A map with HTTP method names upper-cased as the keys, and call routers as the values.
4475    */
4476   protected Map<String,RestCallRouter> getCallRouters() {
4477      return callRouters;
4478   }
4479
4480   /**
4481    * Returns the resource object.
4482    *
4483    * <p>
4484    * This is the instance of the class annotated with the {@link Rest @Rest} annotation, usually
4485    * an instance of {@link RestServlet}.
4486    *
4487    * @return
4488    *    The resource object.
4489    *    <br>Never <jk>null</jk>.
4490    */
4491   public Object getResource() {
4492      return resource;
4493   }
4494
4495   /**
4496    * Returns the resource object as a {@link RestServlet}.
4497    *
4498    * @return
4499    *    The resource object cast to {@link RestServlet}, or <jk>null</jk> if the resource doesn't subclass from
4500    *    {@link RestServlet}.
4501    */
4502   public RestServlet getRestServlet() {
4503      return resource instanceof RestServlet ? (RestServlet)resource : null;
4504   }
4505
4506   /**
4507    * Throws a {@link HttpException} if an exception occurred in the constructor of this object.
4508    *
4509    * @throws HttpException The initialization exception wrapped in a {@link HttpException}.
4510    */
4511   protected void checkForInitException() throws HttpException {
4512      if (initException != null)
4513         throw initException;
4514   }
4515
4516   /**
4517    * Returns the parent resource context (if this resource was initialized from a parent).
4518    *
4519    * <p>
4520    * From this object, you can get access to the parent resource class itself using {@link #getResource()} or
4521    * {@link #getRestServlet()}
4522    *
4523    * @return The parent resource context, or <jk>null</jk> if there is no parent context.
4524    */
4525   public RestContext getParentContext() {
4526      return parentContext;
4527   }
4528
4529   /**
4530    * Returns the class-level properties associated with this servlet.
4531    *
4532    * <p>
4533    * Properties at the class level are defined via the following:
4534    * <ul class='javatree'>
4535    *    <li class='ja'>{@link Rest#properties()}
4536    *    <li class='jm'>{@link RestContextBuilder#set(String, Object)}
4537    *    <li class='jm'>{@link RestContextBuilder#set(Map)}
4538    * </ul>
4539    *
4540    * <ul class='notes'>
4541    *    <li>
4542    *       The returned {@code Map} is mutable.
4543    *       <br>Therefore, subclasses are free to override or set additional initialization parameters in their {@code init()} method.
4544    * </ul>
4545    *
4546    * @return The resource properties as a {@link RestContextProperties}.
4547    */
4548   public RestContextProperties getProperties() {
4549      return properties;
4550   }
4551
4552   /**
4553    * Returns the servlet init parameter returned by {@link ServletConfig#getInitParameter(String)}.
4554    *
4555    * @param name The init parameter name.
4556    * @return The servlet init parameter, or <jk>null</jk> if not found.
4557    */
4558   public String getServletInitParameter(String name) {
4559      return builder.getInitParameter(name);
4560   }
4561
4562   /**
4563    * Returns the child resources associated with this servlet.
4564    *
4565    * @return
4566    *    An unmodifiable map of child resources.
4567    *    Keys are the {@link Rest#path() @Rest(path)} annotation defined on the child resource.
4568    */
4569   public Map<String,RestContext> getChildResources() {
4570      return Collections.unmodifiableMap(childResources);
4571   }
4572
4573   /**
4574    * Returns the number of times this exception was thrown based on a hash of its stacktrace.
4575    *
4576    * <div class='warn'>
4577    *    <b>Deprecated</b> - Not used by new logging API.
4578    * </div>
4579    *
4580    * <ul class='seealso'>
4581    *    <li class='jf'>{@link RestContext#REST_useStackTraceHashes}
4582    * </ul>
4583    *
4584    * @param e The exception to check.
4585    * @return
4586    *    The number of times this exception was thrown, or <c>0</c> if {@link #REST_useStackTraceHashes}
4587    *    setting is not enabled.
4588    */
4589   @Deprecated
4590   public int getStackTraceOccurrence(Throwable e) {
4591      if (! useStackTraceHashes)
4592         return 0;
4593      int h = e.hashCode();
4594      stackTraceHashes.putIfAbsent(h, new AtomicInteger());
4595      return stackTraceHashes.get(h).incrementAndGet();
4596   }
4597
4598   /**
4599    * Returns whether it's safe to render stack traces in HTTP responses.
4600    *
4601    * <ul class='seealso'>
4602    *    <li class='jf'>{@link RestContext#REST_useStackTraceHashes}
4603    * </ul>
4604    *
4605    * @return <jk>true</jk> if setting is enabled.
4606    */
4607   public boolean isRenderResponseStackTraces() {
4608      return renderResponseStackTraces;
4609   }
4610
4611   /**
4612    * Returns whether it's safe to pass the HTTP body as a <js>"body"</js> GET parameter.
4613    *
4614    * <ul class='seealso'>
4615    *    <li class='jf'>{@link RestContext#REST_allowBodyParam}
4616    * </ul>
4617    *
4618    * @return <jk>true</jk> if setting is enabled.
4619    */
4620   public boolean isAllowBodyParam() {
4621      return allowBodyParam;
4622   }
4623
4624   /**
4625    * Allowed header URL parameters.
4626    *
4627    * <ul class='seealso'>
4628    *    <li class='jf'>{@link RestContext#REST_allowedHeaderParams}
4629    * </ul>
4630    *
4631    * @return
4632    *    The header names allowed to be passed as URL parameters.
4633    *    <br>The set is case-insensitive ordered.
4634    */
4635   public Set<String> getAllowedHeaderParams() {
4636      return allowedHeaderParams;
4637   }
4638
4639   /**
4640    * Allowed method headers.
4641    *
4642    * <ul class='seealso'>
4643    *    <li class='jf'>{@link RestContext#REST_allowedMethodHeaders}
4644    * </ul>
4645    *
4646    * @return
4647    *    The method names allowed to be passed as <c>X-Method</c> headers.
4648    *    <br>The set is case-insensitive ordered.
4649    */
4650   public Set<String> getAllowedMethodHeaders() {
4651      return allowedMethodHeaders;
4652   }
4653
4654   /**
4655    * Allowed method URL parameters.
4656    *
4657    * <ul class='seealso'>
4658    *    <li class='jf'>{@link RestContext#REST_allowedMethodParams}
4659    * </ul>
4660    *
4661    * @return
4662    *    The method names allowed to be passed as <c>method</c> URL parameters.
4663    *    <br>The set is case-insensitive ordered.
4664    */
4665   public Set<String> getAllowedMethodParams() {
4666      return allowedMethodParams;
4667   }
4668
4669   /**
4670    * Returns <jk>true</jk> if debug mode is enabled on this resource.
4671    *
4672    * <div class='warn'>
4673    *    <b>Deprecated</b> - Use {@link #getDebug()}
4674    * </div>
4675    *
4676    * <ul class='seealso'>
4677    *    <li class='jf'>{@link RestContext#REST_debug}
4678    * </ul>
4679    *
4680    * @return <jk>true</jk> if setting is enabled.
4681    */
4682   @Deprecated
4683   @Override
4684   public boolean isDebug() {
4685      return debug == Enablement.TRUE;
4686   }
4687
4688   /**
4689    * Returns the debug setting on this context.
4690    *
4691    * @return The debug setting on this context.
4692    */
4693   public Enablement getDebug() {
4694      return debug;
4695   }
4696
4697   /**
4698    * Returns the name of the client version header name used by this resource.
4699    *
4700    * <ul class='seealso'>
4701    *    <li class='jf'>{@link RestContext#REST_clientVersionHeader}
4702    * </ul>
4703    *
4704    * @return
4705    *    The name of the client version header used by this resource.
4706    *    <br>Never <jk>null</jk>.
4707    */
4708   public String getClientVersionHeader() {
4709      return clientVersionHeader;
4710   }
4711
4712   /**
4713    * Returns the HTTP-part parser associated with this resource.
4714    *
4715    * <ul class='seealso'>
4716    *    <li class='jf'>{@link RestContext#REST_partParser}
4717    * </ul>
4718    *
4719    * @return
4720    *    The HTTP-part parser associated with this resource.
4721    *    <br>Never <jk>null</jk>.
4722    */
4723   public HttpPartParser getPartParser() {
4724      return partParser;
4725   }
4726
4727   /**
4728    * Returns the HTTP-part serializer associated with this resource.
4729    *
4730    * <ul class='seealso'>
4731    *    <li class='jf'>{@link RestContext#REST_partSerializer}
4732    * </ul>
4733    *
4734    * @return
4735    *    The HTTP-part serializer associated with this resource.
4736    *    <br>Never <jk>null</jk>.
4737    */
4738   public HttpPartSerializer getPartSerializer() {
4739      return partSerializer;
4740   }
4741
4742   /**
4743    * Returns the JSON-Schema generator associated with this resource.
4744    *
4745    * @return
4746    *    The HTTP-part serializer associated with this resource.
4747    *    <br>Never <jk>null</jk>.
4748    */
4749   public JsonSchemaGenerator getJsonSchemaGenerator() {
4750      return jsonSchemaGenerator;
4751   }
4752
4753   /**
4754    * Returns the explicit list of supported accept types for this resource.
4755    *
4756    * <ul class='seealso'>
4757    *    <li class='jf'>{@link RestContext#REST_serializers}
4758    *    <li class='jf'>{@link RestContext#REST_produces}
4759    * </ul>
4760    *
4761    * @return
4762    *    The supported <c>Accept</c> header values for this resource.
4763    *    <br>Never <jk>null</jk>.
4764    */
4765   public List<MediaType> getProduces() {
4766      return produces;
4767   }
4768
4769   /**
4770    * Returns the explicit list of supported content types for this resource.
4771    *
4772    * <ul class='seealso'>
4773    *    <li class='jf'>{@link RestContext#REST_parsers}
4774    *    <li class='jf'>{@link RestContext#REST_consumes}
4775    * </ul>
4776    *
4777    * @return
4778    *    The supported <c>Content-Type</c> header values for this resource.
4779    *    <br>Never <jk>null</jk>.
4780    */
4781   public List<MediaType> getConsumes() {
4782      return consumes;
4783   }
4784
4785   /**
4786    * Returns the default request headers for this resource.
4787    *
4788    * <ul class='seealso'>
4789    *    <li class='jf'>{@link RestContext#REST_reqHeaders}
4790    * </ul>
4791    *
4792    * @return
4793    *    The default request headers for this resource.
4794    *    <br>Never <jk>null</jk>.
4795    */
4796   public Map<String,Object> getReqHeaders() {
4797      return reqHeaders;
4798   }
4799
4800   /**
4801    * Returns the default request attributes for this resource.
4802    *
4803    * <ul class='seealso'>
4804    *    <li class='jf'>{@link RestContext#REST_reqAttrs}
4805    * </ul>
4806    *
4807    * @return
4808    *    The default request headers for this resource.
4809    *    <br>Never <jk>null</jk>.
4810    */
4811   public ObjectMap getReqAttrs() {
4812      return reqAttrs;
4813   }
4814
4815   /**
4816    * Returns the default response headers for this resource.
4817    *
4818    * <ul class='seealso'>
4819    *    <li class='jf'>{@link RestContext#REST_resHeaders}
4820    * </ul>
4821    *
4822    * @return
4823    *    The default response headers for this resource.
4824    *    <br>Never <jk>null</jk>.
4825    */
4826   public Map<String,Object> getResHeaders() {
4827      return resHeaders;
4828   }
4829
4830   /**
4831    * Returns the response handlers associated with this resource.
4832    *
4833    * <ul class='seealso'>
4834    *    <li class='jf'>{@link RestContext#REST_responseHandlers}
4835    * </ul>
4836    *
4837    * @return
4838    *    The response handlers associated with this resource.
4839    *    <br>Never <jk>null</jk>.
4840    */
4841   protected ResponseHandler[] getResponseHandlers() {
4842      return responseHandlers;
4843   }
4844
4845   /**
4846    * Returns <jk>true</jk> if this resource has any child resources associated with it.
4847    *
4848    * <ul class='seealso'>
4849    *    <li class='jf'>{@link RestContext#REST_children}
4850    * </ul>
4851    *
4852    * @return <jk>true</jk> if this resource has any child resources associated with it.
4853    */
4854   public boolean hasChildResources() {
4855      return ! childResources.isEmpty();
4856   }
4857
4858   /**
4859    * Returns the context of the child resource associated with the specified path.
4860    *
4861    * <ul class='seealso'>
4862    *    <li class='jf'>{@link RestContext#REST_children}
4863    * </ul>
4864    *
4865    * @param path The path of the child resource to resolve.
4866    * @return The resolved context, or <jk>null</jk> if it could not be resolved.
4867    */
4868   public RestContext getChildResource(String path) {
4869      return childResources.get(path);
4870   }
4871
4872   /**
4873    * Returns the authority path of the resource.
4874    *
4875    * <ul class='seealso'>
4876    *    <li class='jf'>{@link RestContext#REST_uriAuthority}
4877    * </ul>
4878    *
4879    * @return
4880    *    The authority path of this resource.
4881    *    <br>If not specified, returns the context path of the ascendant resource.
4882    */
4883   public String getUriAuthority() {
4884      if (uriAuthority != null)
4885         return uriAuthority;
4886      if (parentContext != null)
4887         return parentContext.getUriAuthority();
4888      return null;
4889   }
4890
4891   /**
4892    * Returns the context path of the resource.
4893    *
4894    * <ul class='seealso'>
4895    *    <li class='jf'>{@link RestContext#REST_uriContext}
4896    * </ul>
4897    *
4898    * @return
4899    *    The context path of this resource.
4900    *    <br>If not specified, returns the context path of the ascendant resource.
4901    */
4902   public String getUriContext() {
4903      if (uriContext != null)
4904         return uriContext;
4905      if (parentContext != null)
4906         return parentContext.getUriContext();
4907      return null;
4908   }
4909
4910   /**
4911    * Returns the setting on how relative URIs should be interpreted as relative to.
4912    *
4913    * <ul class='seealso'>
4914    *    <li class='jf'>{@link RestContext#REST_uriRelativity}
4915    * </ul>
4916    *
4917    * @return
4918    *    The URI-resolution relativity setting value.
4919    *    <br>Never <jk>null</jk>.
4920    */
4921   public UriRelativity getUriRelativity() {
4922      return uriRelativity;
4923   }
4924
4925   /**
4926    * Returns the setting on how relative URIs should be resolved.
4927    *
4928    * <ul class='seealso'>
4929    *    <li class='jf'>{@link RestContext#REST_uriResolution}
4930    * </ul>
4931    *
4932    * @return
4933    *    The URI-resolution setting value.
4934    *    <br>Never <jk>null</jk>.
4935    */
4936   public UriResolution getUriResolution() {
4937      return uriResolution;
4938   }
4939
4940   /**
4941    * Returns the parameters defined on the specified Java method.
4942    *
4943    * @param method The Java method to check.
4944    * @return The parameters defined on the Java method.
4945    */
4946   public RestMethodParam[] getRestMethodParams(Method method) {
4947      return callMethods.get(method.getName()).methodParams;
4948   }
4949
4950   /**
4951    * Returns the media type for the specified file name.
4952    *
4953    * <ul class='seealso'>
4954    *    <li class='jf'>{@link RestContext#REST_mimeTypes}
4955    * </ul>
4956    *
4957    * @param name The file name.
4958    * @return The MIME-type, or <jk>null</jk> if it could not be determined.
4959    */
4960   public String getMediaTypeForName(String name) {
4961      return mimetypesFileTypeMap.getContentType(name);
4962   }
4963
4964   /**
4965    * Returns <jk>true</jk> if the specified path refers to a static file.
4966    *
4967    * <p>
4968    * Static files are files pulled from the classpath and served up directly to the browser.
4969    *
4970    * <ul class='seealso'>
4971    *    <li class='jf'>{@link RestContext#REST_staticFiles}
4972    * </ul>
4973    *
4974    * @param p The URL path remainder after the servlet match.
4975    * @return <jk>true</jk> if the specified path refers to a static file.
4976    */
4977   public boolean isStaticFile(String p) {
4978      return pathStartsWith(p, staticFilesPaths);
4979   }
4980
4981   /**
4982    * Returns the REST Java methods defined in this resource.
4983    *
4984    * <p>
4985    * These are the methods annotated with the {@link RestMethod @RestMethod} annotation.
4986    *
4987    * @return
4988    *    An unmodifiable map of Java method names to call method objects.
4989    */
4990   public Map<String,RestMethodContext> getCallMethods() {
4991      return callMethods;
4992   }
4993
4994   /**
4995    * Gives access to the internal stack trace database.
4996    *
4997    * @return The stack trace database.
4998    */
4999   public StackTraceDatabase getStackTraceDb() {
5000      return stackTraceDb;
5001   }
5002
5003   /**
5004    * Returns timing information on all method executions on this class.
5005    *
5006    * <p>
5007    * Timing information is maintained for any <ja>@RestResource</ja>-annotated and hook methods.
5008    *
5009    * @return A list of timing statistics ordered by average execution time descending.
5010    */
5011   public List<MethodExecStats> getMethodExecStats() {
5012      return methodExecStats.values().stream().sorted().collect(Collectors.toList());
5013   }
5014
5015   /**
5016    * Gives access to the internal stack trace database.
5017    *
5018    * @return The stack trace database.
5019    */
5020   public RestContextStats getStats() {
5021      return new RestContextStats(startTime, getMethodExecStats());
5022   }
5023
5024   /**
5025    * Returns the timing information returned by {@link #getMethodExecStats()} in a readable format.
5026    *
5027    * @return A report of all method execution times ordered by .
5028    */
5029   public String getMethodExecStatsReport() {
5030      StringBuilder sb = new StringBuilder()
5031         .append(" Method                         Runs      Running   Errors   Avg          Total     \n")
5032         .append("------------------------------ --------- --------- -------- ------------ -----------\n");
5033      getMethodExecStats()
5034         .stream()
5035         .sorted(Comparator.comparingDouble(MethodExecStats::getTotalTime).reversed())
5036         .forEach(x -> sb.append(String.format("%30s %9d %9d %9d %10dms %10dms\n", x.getMethod(), x.getRuns(), x.getRunning(), x.getErrors(), x.getAvgTime(), x.getTotalTime())));
5037      return sb.toString();
5038   }
5039
5040   /**
5041    * Finds the {@link RestMethodParam} instances to handle resolving objects on the calls to the specified Java method.
5042    *
5043    * @param mi The Java method being called.
5044    * @param isPreOrPost Whether this is a {@link HookEvent#PRE_CALL} or {@link HookEvent#POST_CALL}.
5045    * @param pathPattern The path pattern to match against.
5046    * @return The array of resolvers.
5047    * @throws ServletException If an annotation usage error was detected.
5048    */
5049   protected RestMethodParam[] findParams(MethodInfo mi, boolean isPreOrPost, UrlPathPattern pathPattern) throws ServletException {
5050
5051      List<ClassInfo> pt = mi.getParamTypes();
5052      RestMethodParam[] rp = new RestMethodParam[pt.size()];
5053      PropertyStore ps = getPropertyStore();
5054
5055      for (int i = 0; i < pt.size(); i++) {
5056
5057         ClassInfo t = pt.get(i);
5058         if (t.inner() != null) {
5059            Class<?> c = t.inner();
5060            rp[i] = paramResolvers.get(c);
5061            if (rp[i] == null)
5062               rp[i] = RestParamDefaults.STANDARD_RESOLVERS.get(c);
5063         }
5064
5065         ParamInfo mpi = mi.getParam(i);
5066
5067         if (mpi.hasAnnotation(Header.class)) {
5068            rp[i] = new RestParamDefaults.HeaderObject(mpi, ps);
5069         } else if (mpi.hasAnnotation(Attr.class)) {
5070            rp[i] = new RestParamDefaults.AttributeObject(mpi, ps);
5071         } else if (mpi.hasAnnotation(Query.class)) {
5072            rp[i] = new RestParamDefaults.QueryObject(mpi, ps);
5073         } else if (mpi.hasAnnotation(FormData.class)) {
5074            rp[i] = new RestParamDefaults.FormDataObject(mpi, ps);
5075         } else if (mpi.hasAnnotation(Path.class)) {
5076            rp[i] = new RestParamDefaults.PathObject(mpi, ps, pathPattern);
5077         } else if (mpi.hasAnnotation(Body.class)) {
5078            rp[i] = new RestParamDefaults.BodyObject(mpi, ps);
5079         } else if (mpi.hasAnnotation(Request.class)) {
5080            rp[i] = new RestParamDefaults.RequestObject(mpi, ps);
5081         } else if (mpi.hasAnnotation(Response.class)) {
5082            rp[i] = new RestParamDefaults.ResponseObject(mpi, ps);
5083         } else if (mpi.hasAnnotation(ResponseHeader.class)) {
5084            rp[i] = new RestParamDefaults.ResponseHeaderObject(mpi, ps);
5085         } else if (mpi.hasAnnotation(ResponseStatus.class)) {
5086            rp[i] = new RestParamDefaults.ResponseStatusObject(t);
5087         } else if (mpi.hasAnnotation(HasFormData.class)) {
5088            rp[i] = new RestParamDefaults.HasFormDataObject(mpi);
5089         } else if (mpi.hasAnnotation(HasQuery.class)) {
5090            rp[i] = new RestParamDefaults.HasQueryObject(mpi);
5091         } else if (mpi.hasAnnotation(org.apache.juneau.rest.annotation.Method.class)) {
5092            rp[i] = new RestParamDefaults.MethodObject(mi, t);
5093         }
5094
5095         if (rp[i] == null && ! isPreOrPost)
5096            throw new RestServletException("Invalid parameter specified for method ''{0}'' at index position {1}", mi.inner(), i);
5097      }
5098
5099      return rp;
5100   }
5101
5102   /*
5103    * Calls all @RestHook(PRE) methods.
5104    */
5105   void preCall(RestRequest req, RestResponse res) throws HttpException {
5106      for (int i = 0; i < preCallMethods.length; i++)
5107         preOrPost(resource, preCallMethods[i], preCallMethodParams[i], req, res);
5108   }
5109
5110   /*
5111    * Calls all @RestHook(POST) methods.
5112    */
5113   void postCall(RestRequest req, RestResponse res) throws HttpException {
5114      for (int i = 0; i < postCallMethods.length; i++)
5115         preOrPost(resource, postCallMethods[i], postCallMethodParams[i], req, res);
5116   }
5117
5118   private static void preOrPost(Object resource, MethodInvoker m, RestMethodParam[] mp, RestRequest req, RestResponse res) throws HttpException {
5119      if (m != null) {
5120         Object[] args = new Object[mp.length];
5121         for (int i = 0; i < mp.length; i++) {
5122            try {
5123               args[i] = mp[i].resolve(req, res);
5124            } catch (Exception e) {
5125               throw toHttpException(e, BadRequest.class, "Invalid data conversion.  Could not convert {0} ''{1}'' to type ''{2}'' on method ''{3}.{4}''.", mp[i].getParamType().name(), mp[i].getName(), mp[i].getType(), m.getDeclaringClass().getName(), m.getName());
5126            }
5127         }
5128         try {
5129            m.invoke(resource, args);
5130         } catch (Exception e) {
5131            throw toHttpException(e, InternalServerError.class);
5132         }
5133      }
5134   }
5135
5136   /*
5137    * Calls all @RestHook(START) methods.
5138    */
5139   void startCall(RestCall call) {
5140      for (int i = 0; i < startCallMethods.length; i++)
5141         startOrFinish(resource, startCallMethods[i], startCallMethodParams[i], call.getRequest(), call.getResponse());
5142   }
5143
5144   /*
5145    * Calls all @RestHook(FINISH) methods.
5146    */
5147   void finishCall(RestCall call) {
5148      for (int i = 0; i < endCallMethods.length; i++)
5149         startOrFinish(resource, endCallMethods[i], endCallMethodParams[i], call.getRequest(), call.getResponse());
5150   }
5151
5152   private static void startOrFinish(Object resource, MethodInvoker m, Class<?>[] p, HttpServletRequest req, HttpServletResponse res) throws HttpException, InternalServerError {
5153      if (m != null) {
5154         Object[] args = new Object[p.length];
5155         for (int i = 0; i < p.length; i++) {
5156            if (p[i] == HttpServletRequest.class)
5157               args[i] = req;
5158            else if (p[i] == HttpServletResponse.class)
5159               args[i] = res;
5160         }
5161         try {
5162            m.invoke(resource, args);
5163         } catch (Exception e) {
5164            throw toHttpException(e, InternalServerError.class);
5165         }
5166      }
5167   }
5168
5169   /**
5170    * Calls all @RestHook(POST_INIT) methods in parent-to-child order.
5171    *
5172    * @return This object (for method chaining).
5173    * @throws ServletException Error occurred.
5174    */
5175   public RestContext postInit() throws ServletException {
5176      for (int i = 0; i < postInitMethods.length; i++)
5177         postInitOrDestroy(resource, postInitMethods[i], postInitMethodParams[i]);
5178      for (RestContext childContext : this.childResources.values())
5179         childContext.postInit();
5180      return this;
5181   }
5182
5183   /**
5184    * Calls all @RestHook(POST_INIT_CHILD_FIRST) methods in child-to-parent order.
5185    *
5186    * @return This object (for method chaining).
5187    * @throws ServletException Error occurred.
5188    */
5189   public RestContext postInitChildFirst() throws ServletException {
5190      for (RestContext childContext : this.childResources.values())
5191         childContext.postInitChildFirst();
5192      for (int i = 0; i < postInitChildFirstMethods.length; i++)
5193         postInitOrDestroy(resource, postInitChildFirstMethods[i], postInitChildFirstMethodParams[i]);
5194      return this;
5195   }
5196
5197   private void postInitOrDestroy(Object r, MethodInvoker m, Class<?>[] p) {
5198      if (m != null) {
5199         Object[] args = new Object[p.length];
5200         for (int i = 0; i < p.length; i++) {
5201            if (p[i] == RestContext.class)
5202               args[i] = this;
5203            else if (p[i] == RestContextBuilder.class)
5204               args[i] = this.builder;
5205            else if (p[i] == ServletConfig.class)
5206               args[i] = this.builder.inner;
5207         }
5208         try {
5209            m.invoke(r, args);
5210         } catch (Exception e) {
5211            if (e instanceof RuntimeException && ClassInfo.of(e).hasAnnotation(Response.class))
5212               throw (RuntimeException)e;
5213            throw new InternalServerError(e);
5214         }
5215      }
5216   }
5217
5218   /**
5219    * Calls {@link Servlet#destroy()} on any child resources defined on this resource.
5220    */
5221   protected void destroy() {
5222      for (int i = 0; i < destroyMethods.length; i++) {
5223         try {
5224            postInitOrDestroy(resource, destroyMethods[i], destroyMethodParams[i]);
5225         } catch (Exception e) {
5226            e.printStackTrace();
5227         }
5228      }
5229
5230      for (RestContext r : childResources.values()) {
5231         r.destroy();
5232         if (r.resource instanceof Servlet)
5233            ((Servlet)r.resource).destroy();
5234      }
5235   }
5236
5237   /**
5238    * Returns the HTTP request object for the current request.
5239    *
5240    * @return The HTTP request object, or <jk>null</jk> if it hasn't been created.
5241    */
5242   public RestRequest getRequest() {
5243      return req.get();
5244   }
5245
5246   void setRequest(RestRequest req) {
5247      // Must be careful not to bleed thread-locals.
5248      if (this.req.get() != null)
5249         System.err.println("WARNING:  Thread-local request object was not cleaned up from previous request.  " + this + ", thread=["+Thread.currentThread().getId()+"]");
5250      this.req.set(req);
5251   }
5252
5253   /**
5254    * Returns the HTTP response object for the current request.
5255    *
5256    * @return The HTTP response object, or <jk>null</jk> if it hasn't been created.
5257    */
5258   public RestResponse getResponse() {
5259      return res.get();
5260   }
5261
5262   void setResponse(RestResponse res) {
5263      // Must be careful not to bleed thread-locals.
5264      if (this.res.get() != null)
5265         System.err.println("WARNING:  Thread-local response object was not cleaned up from previous request.  " + this + ", thread=["+Thread.currentThread().getId()+"]");
5266      this.res.set(res);
5267   }
5268
5269   /**
5270    * Clear any request state information on this context.
5271    * This should always be called in a finally block in the RestServlet.
5272    */
5273   void clearState() {
5274      req.remove();
5275      res.remove();
5276   }
5277
5278   //-----------------------------------------------------------------------------------------------------------------
5279   // Other methods.
5280   //-----------------------------------------------------------------------------------------------------------------
5281
5282   @Override /* Context */
5283   public ObjectMap toMap() {
5284      return super.toMap()
5285         .append("RestContext", new DefaultFilteringObjectMap()
5286            .append("allowBodyParam", allowBodyParam)
5287            .append("allowedMethodHeader", allowedMethodHeaders)
5288            .append("allowedMethodParams", allowedMethodParams)
5289            .append("allowedHeaderParams", allowedHeaderParams)
5290            .append("callHandler", callHandler)
5291            .append("clientVersionHeader", clientVersionHeader)
5292            .append("consumes", consumes)
5293            .append("infoProvider", infoProvider)
5294            .append("logger", logger)
5295            .append("paramResolvers", paramResolvers)
5296            .append("parsers", parsers)
5297            .append("partParser", partParser)
5298            .append("partSerializer", partSerializer)
5299            .append("produces", produces)
5300            .append("properties", properties)
5301            .append("renderResponseStackTraces", renderResponseStackTraces)
5302            .append("reqHeaders", reqHeaders)
5303            .append("resHeaders", resHeaders)
5304            .append("resourceResolver", resourceResolver)
5305            .append("responseHandlers", responseHandlers)
5306            .append("serializers", serializers)
5307            .append("staticFileResponseHeaders", staticFileResponseHeaders)
5308            .append("staticFiles", staticFiles)
5309            .append("uriAuthority", uriAuthority)
5310            .append("uriContext", uriContext)
5311            .append("uriRelativity", uriRelativity)
5312            .append("uriResolution", uriResolution)
5313            .append("useClasspathResourceCaching", useClasspathResourceCaching)
5314         );
5315   }
5316}