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