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