001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest;
014
015import static org.apache.juneau.internal.CollectionUtils.*;
016import static org.apache.juneau.internal.ObjectUtils.*;
017import static org.apache.juneau.collections.JsonMap.*;
018import static org.apache.juneau.common.internal.StringUtils.*;
019import static org.apache.juneau.common.internal.ThrowableUtils.*;
020import static org.apache.juneau.http.HttpHeaders.*;
021import static org.apache.juneau.http.HttpParts.*;
022import static org.apache.juneau.httppart.HttpPartType.*;
023import static org.apache.juneau.rest.util.RestUtils.*;
024import java.lang.annotation.*;
025import java.lang.reflect.Method;
026import java.nio.charset.*;
027import java.util.*;
028import java.util.concurrent.*;
029import java.util.function.*;
030
031import jakarta.servlet.*;
032import jakarta.servlet.http.*;
033
034import org.apache.http.*;
035import org.apache.juneau.*;
036import org.apache.juneau.annotation.*;
037import org.apache.juneau.collections.*;
038import org.apache.juneau.common.internal.*;
039import org.apache.juneau.cp.*;
040import org.apache.juneau.encoders.*;
041import org.apache.juneau.http.annotation.*;
042import org.apache.juneau.http.annotation.Header;
043import org.apache.juneau.http.header.*;
044import org.apache.juneau.http.part.*;
045import org.apache.juneau.http.remote.*;
046import org.apache.juneau.httppart.*;
047import org.apache.juneau.httppart.bean.*;
048import org.apache.juneau.internal.*;
049import org.apache.juneau.internal.HttpUtils;
050import org.apache.juneau.jsonschema.*;
051import org.apache.juneau.parser.*;
052import org.apache.juneau.parser.ParseException;
053import org.apache.juneau.reflect.*;
054import org.apache.juneau.rest.annotation.*;
055import org.apache.juneau.rest.converter.*;
056import org.apache.juneau.rest.debug.*;
057import org.apache.juneau.rest.guard.*;
058import org.apache.juneau.rest.httppart.*;
059import org.apache.juneau.rest.logger.*;
060import org.apache.juneau.http.response.*;
061import org.apache.juneau.rest.matcher.*;
062import org.apache.juneau.rest.swagger.*;
063import org.apache.juneau.rest.util.*;
064import org.apache.juneau.serializer.*;
065import org.apache.juneau.svl.*;
066import org.apache.juneau.utils.*;
067
068/**
069 * Represents a single Java servlet/resource method annotated with {@link RestOp @RestOp}.
070 *
071 * <h5 class='section'>Notes:</h5><ul>
072 *    <li class='note'>This class is thread safe and reusable.
073 * </ul>
074 *
075 * <h5 class='section'>See Also:</h5><ul>
076 *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.RestOpContext">RestOpContext</a>
077 * </ul>
078 */
079public class RestOpContext extends Context implements Comparable<RestOpContext>  {
080
081   //-------------------------------------------------------------------------------------------------------------------
082   // Static
083   //-------------------------------------------------------------------------------------------------------------------
084
085   /**
086    * Creates a new builder for this object.
087    *
088    * @param method The Java method this context belongs to.
089    * @param context The Java class context.
090    * @return A new builder.
091    */
092   public static Builder create(java.lang.reflect.Method method, RestContext context) {
093      return new Builder(method, context);
094   }
095
096   //-------------------------------------------------------------------------------------------------------------------
097   // Builder
098   //-------------------------------------------------------------------------------------------------------------------
099
100   /**
101    * Builder class.
102    */
103   @FluentSetters
104   public static final class Builder extends Context.Builder {
105
106      RestContext restContext;
107      RestContext.Builder parent;
108      Method restMethod;
109      String httpMethod, clientVersion;
110      Enablement debug;
111      List<String> path;
112
113      private RestConverterList.Builder converters;
114      private BeanContext.Builder beanContext;
115      private RestGuardList.Builder guards;
116      private EncoderSet.Builder encoders;
117      private SerializerSet.Builder serializers;
118      private ParserSet.Builder parsers;
119      private HttpPartSerializer.Creator partSerializer;
120      private HttpPartParser.Creator partParser;
121      private RestMatcherList.Builder matchers;
122      private JsonSchemaGenerator.Builder jsonSchemaGenerator;
123
124      PartList defaultRequestFormData, defaultRequestQueryData;
125      NamedAttributeMap defaultRequestAttributes;
126      HeaderList defaultRequestHeaders, defaultResponseHeaders;
127      RestMatcherList.Builder restMatchers;
128      List<MediaType> produces, consumes;
129      Set<String> roleGuard, rolesDeclared;
130      boolean dotAll;
131
132      Charset defaultCharset;
133      Long maxInput;
134
135      private BeanStore beanStore;
136
137      @Override /* Context.Builder */
138      public Builder copy() {
139         throw new NoSuchMethodError("Not implemented.");
140      }
141
142      @Override /* BeanContext.Builder */
143      public RestOpContext build() {
144         try {
145            return beanStore.createBean(RestOpContext.class).type(getType().orElse(getDefaultImplClass())).builder(RestOpContext.Builder.class, this).run();
146         } catch (Exception e) {
147            throw new InternalServerError(e);
148         }
149      }
150
151      /**
152       * Specifies the default implementation class if not specified via {@link #type(Class)}.
153       *
154       * @return The default implementation class if not specified via {@link #type(Class)}.
155       */
156      protected Class<? extends RestOpContext> getDefaultImplClass() {
157         return RestOpContext.class;
158      }
159
160      Builder(java.lang.reflect.Method method, RestContext context) {
161
162         this.restContext = context;
163         this.parent = context.builder;
164         this.restMethod = method;
165
166         this.beanStore = BeanStore
167            .of(context.getBeanStore(), context.builder.resource().get())
168            .addBean(java.lang.reflect.Method.class, method);
169
170         MethodInfo mi = MethodInfo.of(context.getResourceClass(), method);
171
172         try {
173
174            VarResolver vr = context.getVarResolver();
175            VarResolverSession vrs = vr.createSession();
176            AnnotationWorkList work = AnnotationWorkList.of(vrs, mi.getAnnotationList(CONTEXT_APPLY_FILTER));
177
178            apply(work);
179
180            if (context.builder.beanContext().canApply(work))
181               beanContext().apply(work);
182            if (context.builder.serializers().canApply(work))
183               serializers().apply(work);
184            if (context.builder.parsers().canApply(work))
185               parsers().apply(work);
186            if (context.builder.partSerializer().canApply(work))
187               partSerializer().apply(work);
188            if (context.builder.partParser().canApply(work))
189               partParser().apply(work);
190            if (context.builder.jsonSchemaGenerator().canApply(work))
191               jsonSchemaGenerator().apply(work);
192
193            processParameterAnnotations();
194
195         } catch (Exception e) {
196            throw new InternalServerError(e);
197         }
198      }
199
200      /**
201       * Returns the REST servlet/bean instance that this context is defined against.
202       *
203       * @return The REST servlet/bean instance that this context is defined against.
204       */
205      public Supplier<?> resource() {
206         return restContext.builder.resource();
207      }
208
209      /**
210       * Returns the default classes list.
211       *
212       * <p>
213       * This defines the implementation classes for a variety of bean types.
214       *
215       * <p>
216       * Default classes are inherited from the parent REST object.
217       * Typically used on the top-level {@link RestContext.Builder} to affect class types for that REST object and all children.
218       *
219       * <p>
220       * Modifying the default class list on this builder does not affect the default class list on the parent builder, but changes made
221       * here are inherited by child builders.
222       *
223       * @return The default classes list for this builder.
224       */
225      public DefaultClassList defaultClasses() {
226         return restContext.builder.defaultClasses();
227      }
228
229      //-----------------------------------------------------------------------------------------------------------------
230      // beanStore
231      //-----------------------------------------------------------------------------------------------------------------
232
233      /**
234       * Returns access to the bean store being used by this builder.
235       *
236       * <p>
237       * Can be used to add more beans to the bean store.
238       *
239       * @return The bean store being used by this builder.
240       */
241      public BeanStore beanStore() {
242         return beanStore;
243      }
244
245      /**
246       * Specifies a {@link BeanStore} to use when resolving constructor arguments.
247       *
248       * @param beanStore The bean store to use for resolving constructor arguments.
249       * @return This object.
250       */
251      protected Builder beanStore(BeanStore beanStore) {
252         this.beanStore = beanStore;
253         return this;
254      }
255
256      /**
257       * Adds a bean to the bean store of this operation.
258       *
259       * <p>
260       * Equivalent to calling:
261       * <p class='bjava'>
262       *    <jv>builder</jv>.beanStore().add(<jv>beanType</jv>, <jv>bean</jv>);
263       * </p>
264       *
265       * @param <T> The class to associate this bean with.
266       * @param beanType The class to associate this bean with.
267       * @param bean The bean.  Can be <jk>null</jk>.
268       * @return This object.
269       */
270      public <T> Builder beanStore(Class<T> beanType, T bean) {
271         beanStore().addBean(beanType, bean);
272         return this;
273      }
274
275      /**
276       * Adds a bean to the bean store of this operation.
277       *
278       * <p>
279       * Equivalent to calling:
280       * <p class='bjava'>
281       *    <jv>builder</jv>.beanStore().add(<jv>beanType</jv>, <jv>bean</jv>, <jv>name</jv>);
282       * </p>
283       *
284       * @param <T> The class to associate this bean with.
285       * @param beanType The class to associate this bean with.
286       * @param bean The bean.  Can be <jk>null</jk>.
287       * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
288       * @return This object.
289       */
290      public <T> Builder beanStore(Class<T> beanType, T bean, String name) {
291         beanStore().addBean(beanType, bean, name);
292         return this;
293      }
294
295      //-----------------------------------------------------------------------------------------------------------------
296      // beanContext
297      //-----------------------------------------------------------------------------------------------------------------
298
299      /**
300       * Returns the bean context sub-builder.
301       *
302       * @return The bean context sub-builder.
303       */
304      public BeanContext.Builder beanContext() {
305         if (beanContext == null)
306            beanContext = createBeanContext(beanStore(), parent, resource());
307         return beanContext;
308      }
309
310      /**
311       * Instantiates the bean context sub-builder.
312       *
313       * @param beanStore
314       *    The factory used for creating beans and retrieving injected beans.
315       * @param parent
316       *    The builder for the REST resource class.
317       * @param resource
318       *    The REST servlet/bean instance that this context is defined against.
319       * @return A new bean context sub-builder.
320       */
321      protected BeanContext.Builder createBeanContext(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
322
323         // Default value.
324         Value<BeanContext.Builder> v = Value.of(
325            parent.beanContext().copy()
326         );
327
328         // Replace with bean from:  @RestInject(methodScope="foo") public [static] BeanContext xxx(<args>)
329         BeanStore
330            .of(beanStore, resource)
331            .addBean(BeanContext.Builder.class, v.get())
332            .createMethodFinder(BeanContext.class, resource)
333            .find(x -> matches(x))
334            .run(x -> v.get().impl(x));
335
336         return v.get();
337      }
338
339      Optional<BeanContext> getBeanContext() {
340         return optional(beanContext).map(x -> x.build());
341      }
342
343      //-----------------------------------------------------------------------------------------------------------------
344      // encoders
345      //-----------------------------------------------------------------------------------------------------------------
346
347      /**
348       * Returns the encoder group sub-builder.
349       *
350       * @return The encoder group sub-builder.
351       */
352      public EncoderSet.Builder encoders() {
353         if (encoders == null)
354            encoders = createEncoders(beanStore(), parent, resource());
355         return encoders;
356      }
357
358      /**
359       * Adds one or more encoders to this operation.
360       *
361       * <p>
362       * Equivalent to calling:
363       * <p class='bjava'>
364       *    <jv>builder</jv>.encoders().add(<jv>value</jv>);
365       * </p>
366       *
367       * @param value The values to add.
368       * @return This object.
369       */
370      @SafeVarargs
371      public final Builder encoders(Class<? extends Encoder>...value) {
372         encoders().add(value);
373         return this;
374      }
375
376      /**
377       * Adds one or more encoders to this operation.
378       *
379       * <p>
380       * Equivalent to calling:
381       * <p class='bjava'>
382       *    <jv>builder</jv>.encoders().add(<jv>value</jv>);
383       * </p>
384       *
385       * @param value The values to add.
386       * @return This object.
387       */
388      public Builder encoders(Encoder...value) {
389         encoders().add(value);
390         return this;
391      }
392
393      /**
394       * Instantiates the encoder group sub-builder.
395       *
396       * @param beanStore
397       *    The factory used for creating beans and retrieving injected beans.
398       * @param parent
399       *    The builder for the REST resource class.
400       * @param resource
401       *    The REST servlet/bean instance that this context is defined against.
402       * @return A new encoder group sub-builder.
403       */
404      protected EncoderSet.Builder createEncoders(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
405
406         // Default value.
407         Value<EncoderSet.Builder> v = Value.of(
408            parent.encoders().copy()
409         );
410
411         // Replace with bean from:  @RestInject(methodScope="foo") public [static] EncoderSet xxx(<args>)
412         BeanStore
413            .of(beanStore, resource)
414            .addBean(EncoderSet.Builder.class, v.get())
415            .createMethodFinder(EncoderSet.class, resource)
416            .find(x -> matches(x))
417            .run(x -> v.get().impl(x));
418
419         return v.get();
420      }
421
422      Optional<EncoderSet> getEncoders() {
423         return optional(encoders).map(x -> x.build());
424      }
425
426      //-----------------------------------------------------------------------------------------------------------------
427      // serializers
428      //-----------------------------------------------------------------------------------------------------------------
429
430      /**
431       * Returns the serializer group sub-builder.
432       *
433       * @return The serializer group sub-builder.
434       */
435      public SerializerSet.Builder serializers() {
436         if (serializers == null)
437            serializers = createSerializers(beanStore(), parent, resource());
438         return serializers;
439      }
440
441      /**
442       * Adds one or more serializers to this operation.
443       *
444       * <p>
445       * Equivalent to calling:
446       * <p class='bjava'>
447       *    <jv>builder</jv>.serializers().add(<jv>value</jv>);
448       * </p>
449       *
450       * @param value The values to add.
451       * @return This object.
452       */
453      @SafeVarargs
454      public final Builder serializers(Class<? extends Serializer>...value) {
455         serializers().add(value);
456         return this;
457      }
458
459      /**
460       * Adds one or more serializers to this operation.
461       *
462       * <p>
463       * Equivalent to calling:
464       * <p class='bjava'>
465       *    <jv>builder</jv>.serializers().add(<jv>value</jv>);
466       * </p>
467       *
468       * @param value The values to add.
469       * @return This object.
470       */
471      public Builder serializers(Serializer...value) {
472         serializers().add(value);
473         return this;
474      }
475
476      /**
477       * Instantiates the serializer group sub-builder.
478       *
479       * @param beanStore
480       *    The factory used for creating beans and retrieving injected beans.
481       * @param parent
482       *    The builder for the REST resource class.
483       * @param resource
484       *    The REST servlet/bean instance that this context is defined against.
485       * @return A new serializer group sub-builder.
486       */
487      protected SerializerSet.Builder createSerializers(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
488
489         // Default value.
490         Value<SerializerSet.Builder> v = Value.of(
491            parent.serializers().copy()
492         );
493
494         // Replace with bean from:  @RestInject(methodScope="foo") public [static] SerializerSet xxx(<args>)
495         BeanStore
496            .of(beanStore, resource)
497            .addBean(SerializerSet.Builder.class, v.get())
498            .createMethodFinder(SerializerSet.class, resource)
499            .find(x -> matches(x))
500            .run(x -> v.get().impl(x));
501
502         return v.get();
503      }
504
505      Optional<SerializerSet> getSerializers() {
506         return optional(serializers).map(x -> x.build());
507      }
508
509      //-----------------------------------------------------------------------------------------------------------------
510      // parsers
511      //-----------------------------------------------------------------------------------------------------------------
512
513      /**
514       * Returns the parser group sub-builder.
515       *
516       * @return The parser group sub-builder.
517       */
518      public ParserSet.Builder parsers() {
519         if (parsers == null)
520            parsers = createParsers(beanStore(), parent, resource());
521         return parsers;
522      }
523
524      /**
525       * Adds one or more parsers to this operation.
526       *
527       * <p>
528       * Equivalent to calling:
529       * <p class='bjava'>
530       *    <jv>builder</jv>.parsers().add(<jv>value</jv>);
531       * </p>
532       *
533       * @param value The values to add.
534       * @return This object.
535       */
536      @SafeVarargs
537      public final Builder parsers(Class<? extends Parser>...value) {
538         parsers().add(value);
539         return this;
540      }
541
542      /**
543       * Adds one or more parsers to this operation.
544       *
545       * <p>
546       * Equivalent to calling:
547       * <p class='bjava'>
548       *    <jv>builder</jv>.parsers().add(<jv>value</jv>);
549       * </p>
550       *
551       * @param value The values to add.
552       * @return This object.
553       */
554      public Builder parsers(Parser...value) {
555         parsers().add(value);
556         return this;
557      }
558
559      /**
560       * Instantiates the parser group sub-builder.
561       *
562       * @param beanStore
563       *    The factory used for creating beans and retrieving injected beans.
564       * @param parent
565       *    The builder for the REST resource class.
566       * @param resource
567       *    The REST servlet/bean instance that this context is defined against.
568       * @return A new parser group sub-builder.
569       */
570      protected ParserSet.Builder createParsers(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
571
572         // Default value.
573         Value<ParserSet.Builder> v = Value.of(
574            parent.parsers().copy()
575         );
576
577         // Replace with bean from:  @RestInject(methodScope="foo") public [static] ParserSet xxx(<args>)
578         BeanStore
579            .of(beanStore, resource)
580            .addBean(ParserSet.Builder.class, v.get())
581            .createMethodFinder(ParserSet.class, resource)
582            .find(x -> matches(x))
583            .run(x -> v.get().impl(x));
584
585         return v.get();
586      }
587
588      Optional<ParserSet> getParsers() {
589         return optional(parsers).map(x -> x.build());
590      }
591
592      //-----------------------------------------------------------------------------------------------------------------
593      // partSerializer
594      //-----------------------------------------------------------------------------------------------------------------
595
596      /**
597       * Returns the part serializer sub-builder.
598       *
599       * @return The part serializer sub-builder.
600       */
601      public HttpPartSerializer.Creator partSerializer() {
602         if (partSerializer == null)
603            partSerializer = createPartSerializer(beanStore(), parent, resource());
604         return partSerializer;
605      }
606
607      /**
608       * Specifies the part serializer to use for serializing HTTP parts for this operation.
609       *
610       * <p>
611       * Equivalent to calling:
612       * <p class='bjava'>
613       *    <jv>builder</jv>.partSerializer().type(<jv>value</jv>);
614       * </p>
615       *
616       * @param value The new value.
617       * @return This object.
618       */
619      public Builder partSerializer(Class<? extends HttpPartSerializer> value) {
620         partSerializer().type(value);
621         return this;
622      }
623
624      /**
625       * Specifies the part serializer to use for serializing HTTP parts for this operation.
626       *
627       * <p>
628       * Equivalent to calling:
629       * <p class='bjava'>
630       *    <jv>builder</jv>.partSerializer().impl(<jv>value</jv>);
631       * </p>
632       *
633       * @param value The new value.
634       * @return This object.
635       */
636      public Builder partSerializer(HttpPartSerializer value) {
637         partSerializer().impl(value);
638         return this;
639      }
640
641      /**
642       * Instantiates the part serializer sub-builder.
643       *
644       * @param beanStore
645       *    The factory used for creating beans and retrieving injected beans.
646       * @param parent
647       *    The builder for the REST resource class.
648       * @param resource
649       *    The REST servlet/bean instance that this context is defined against.
650       * @return A new part serializer sub-builder.
651       */
652      protected HttpPartSerializer.Creator createPartSerializer(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
653
654         // Default value.
655         Value<HttpPartSerializer.Creator> v = Value.of(
656            parent.partSerializer().copy()
657         );
658
659         // Replace with bean from:  @RestInject(methodScope="foo") public [static] HttpPartSerializer xxx(<args>)
660         BeanStore
661            .of(beanStore, resource)
662            .addBean(HttpPartSerializer.Creator.class, v.get())
663            .createMethodFinder(HttpPartSerializer.class, resource)
664            .find(x -> matches(x))
665            .run(x -> v.get().impl(x));
666
667         return v.get();
668      }
669
670      Optional<HttpPartSerializer> getPartSerializer() {
671         return optional(partSerializer).map(x -> x.create());
672      }
673
674      //-----------------------------------------------------------------------------------------------------------------
675      // partParser
676      //-----------------------------------------------------------------------------------------------------------------
677
678      /**
679       * Returns the part parser sub-builder.
680       *
681       * @return The part parser sub-builder.
682       */
683      public HttpPartParser.Creator partParser() {
684         if (partParser == null)
685            partParser = createPartParser(beanStore(), parent, resource());
686         return partParser;
687      }
688
689      /**
690       * Specifies the part parser to use for parsing HTTP parts for this operation.
691       *
692       * <p>
693       * Equivalent to calling:
694       * <p class='bjava'>
695       *    <jv>builder</jv>.partParser().type(<jv>value</jv>);
696       * </p>
697       *
698       * @param value The new value.
699       * @return This object.
700       */
701      public Builder partParser(Class<? extends HttpPartParser> value) {
702         partParser().type(value);
703         return this;
704      }
705
706      /**
707       * Specifies the part parser to use for parsing HTTP parts for this operation.
708       *
709       * <p>
710       * Equivalent to calling:
711       * <p class='bjava'>
712       *    <jv>builder</jv>.partParser().impl(<jv>value</jv>);
713       * </p>
714       *
715       * @param value The new value.
716       * @return This object.
717       */
718      public Builder partParser(HttpPartParser value) {
719         partParser().impl(value);
720         return this;
721      }
722
723      /**
724       * Instantiates the part parser sub-builder.
725       *
726       * @param beanStore
727       *    The factory used for creating beans and retrieving injected beans.
728       * @param parent
729       *    The builder for the REST resource class.
730       * @param resource
731       *    The REST servlet/bean instance that this context is defined against.
732       * @return A new part parser sub-builder.
733       */
734      protected HttpPartParser.Creator createPartParser(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
735
736         // Default value.
737         Value<HttpPartParser.Creator> v = Value.of(
738            parent.partParser().copy()
739         );
740
741         // Replace with bean from:  @RestInject(methodScope="foo") public [static] HttpPartParser xxx(<args>)
742         BeanStore
743            .of(beanStore, resource)
744            .addBean(HttpPartParser.Creator.class, v.get())
745            .createMethodFinder(HttpPartParser.class, resource)
746            .find(x -> matches(x))
747            .run(x -> v.get().impl(x));
748
749         return v.get();
750      }
751
752      Optional<HttpPartParser> getPartParser() {
753         return optional(partParser).map(x -> x.create());
754      }
755
756      //-----------------------------------------------------------------------------------------------------------------
757      // jsonSchemaGenerator
758      //-----------------------------------------------------------------------------------------------------------------
759
760      /**
761       * Returns the JSON schema generator sub-builder.
762       *
763       * @return The JSON schema generator sub-builder.
764       */
765      public JsonSchemaGenerator.Builder jsonSchemaGenerator() {
766         if (jsonSchemaGenerator == null)
767            jsonSchemaGenerator = createJsonSchemaGenerator(beanStore(), parent, resource());
768         return jsonSchemaGenerator;
769      }
770
771      /**
772       * Specifies the JSON schema generator for this operation.
773       *
774       * <p>
775       * Equivalent to calling:
776       * <p class='bjava'>
777       *    <jv>builder</jv>.jsonSchemaGenerator().type(<jv>value</jv>);
778       * </p>
779       *
780       * @param value The new value.
781       * @return This object.
782       */
783      public Builder jsonSchemaGenerator(Class<? extends JsonSchemaGenerator> value) {
784         jsonSchemaGenerator().type(value);
785         return this;
786      }
787
788      /**
789       * Specifies the JSON schema generator for this operation.
790       *
791       * <p>
792       * Equivalent to calling:
793       * <p class='bjava'>
794       *    <jv>builder</jv>.jsonSchemaGenerator().impl(<jv>value</jv>);
795       * </p>
796       *
797       * @param value The new value.
798       * @return This object.
799       */
800      public Builder jsonSchemaGenerator(JsonSchemaGenerator value) {
801         jsonSchemaGenerator().impl(value);
802         return this;
803      }
804
805      /**
806       * Instantiates the JSON schema generator sub-builder.
807       *
808       * @param beanStore
809       *    The factory used for creating beans and retrieving injected beans.
810       * @param parent
811       *    The builder for the REST resource class.
812       * @param resource
813       *    The REST servlet/bean instance that this context is defined against.
814       * @return A new JSON schema generator sub-builder.
815       */
816      protected JsonSchemaGenerator.Builder createJsonSchemaGenerator(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
817
818         // Default value.
819         Value<JsonSchemaGenerator.Builder> v = Value.of(
820            parent.jsonSchemaGenerator().copy()
821         );
822
823         // Replace with bean from:  @RestInject(methodScope="foo") public [static] JsonSchemaGenerator xxx(<args>)
824         BeanStore
825            .of(beanStore, resource)
826            .addBean(JsonSchemaGenerator.Builder.class, v.get())
827            .createMethodFinder(JsonSchemaGenerator.class, resource)
828            .find(x -> matches(x))
829            .run(x -> v.get().impl(x));
830
831         return v.get();
832      }
833
834      Optional<JsonSchemaGenerator> getJsonSchemaGenerator() {
835         return optional(jsonSchemaGenerator).map(x -> x.build());
836      }
837
838      //-----------------------------------------------------------------------------------------------------------------
839      // converters
840      //-----------------------------------------------------------------------------------------------------------------
841
842      /**
843       * Returns the response converter list sub-builder.
844       *
845       * @return The response converter list sub-builder.
846       */
847      public RestConverterList.Builder converters() {
848         if (converters == null)
849            converters = createConverters(beanStore(), resource());
850         return converters;
851      }
852
853      /**
854       * Adds one or more converters to use to convert response objects for this operation.
855       *
856       * <p>
857       * Equivalent to calling:
858       * <p class='bjava'>
859       *    <jv>builder</jv>.converters().append(<jv>value</jv>);
860       * </p>
861       *
862       * @param value The new value.
863       * @return This object.
864       */
865      @SafeVarargs
866      public final Builder converters(Class<? extends RestConverter>...value) {
867         converters().append(value);
868         return this;
869      }
870
871      /**
872       * Adds one or more converters to this operation.
873       *
874       * <p>
875       * Equivalent to calling:
876       * <p class='bjava'>
877       *    <jv>builder</jv>.converters().append(<jv>value</jv>);
878       * </p>
879       *
880       * @param value The new value.
881       * @return This object.
882       */
883      public Builder converters(RestConverter...value) {
884         converters().append(value);
885         return this;
886      }
887
888      /**
889       * Instantiates the response converter list sub-builder.
890       *
891       * <p>
892       * Associates one or more {@link RestConverter converters} with a resource class.
893       * <br>These converters get called immediately after execution of the REST method in the same order specified in the
894       * annotation.
895       * <br>The object passed into this converter is the object returned from the Java method or passed into
896       * the {@link RestResponse#setContent(Object)} method.
897       *
898       * <p>
899       * Can be used for performing post-processing on the response object before serialization.
900       *
901       * <p>
902       *    When multiple converters are specified, they're executed in the order they're specified in the annotation
903       *    (e.g. first the results will be traversed, then the resulting node will be searched/sorted).
904       *
905       * <h5 class='section'>Example:</h5>
906       * <p class='bjava'>
907       *    <jc>// Our converter.</jc>
908       *    <jk>public class</jk> MyConverter <jk>implements</jk> RestConverter {
909       *       <ja>@Override</ja>
910       *       <jk>public</jk> Object convert(RestRequest <jv>req</jv>, Object <jv>object</jv>) {
911       *          <jc>// Do something with object and return another object.</jc>
912       *          <jc>// Or just return the same object for a no-op.</jc>
913       *       }
914       *    }
915       *
916       *    <jc>// Option #1 - Registered via annotation resolving to a config file setting with default value.</jc>
917       *    <ja>@Rest</ja>(converters={MyConverter.<jk>class</jk>})
918       *    <jk>public class</jk> MyResource {
919       *
920       *       <jc>// Option #2 - Registered via builder passed in through resource constructor.</jc>
921       *       <jk>public</jk> MyResource(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
922       *
923       *          <jc>// Using method on builder.</jc>
924       *          <jv>builder</jv>.converters(MyConverter.<jk>class</jk>);
925       *
926       *          <jc>// Pass in an instance instead.</jc>
927       *          <jv>builder</jv>.converters(<jk>new</jk> MyConverter());
928       *       }
929       *
930       *       <jc>// Option #3 - Registered via builder passed in through init method.</jc>
931       *       <ja>@RestInit</ja>
932       *       <jk>public void</jk> init(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
933       *          <jv>builder</jv>.converters(MyConverter.<jk>class</jk>);
934       *       }
935       *    }
936       * </p>
937       *
938       * <h5 class='section'>Notes:</h5><ul>
939       *    <li class='note'>
940       *       When defined as a class, the implementation must have one of the following constructors:
941       *       <ul>
942       *          <li><code><jk>public</jk> T(BeanContext)</code>
943       *          <li><code><jk>public</jk> T()</code>
944       *          <li><code><jk>public static</jk> T <jsm>create</jsm>(RestContext)</code>
945       *          <li><code><jk>public static</jk> T <jsm>create</jsm>()</code>
946       *       </ul>
947       *    <li class='note'>
948       *       Inner classes of the REST resource class are allowed.
949       * </ul>
950       *
951       * <h5 class='section'>See Also:</h5><ul>
952       *    <li class='jc'>{@link Traversable} - Allows URL additional path info to address individual elements in a POJO tree.
953       *    <li class='jc'>{@link Queryable} - Allows query/view/sort functions to be performed on POJOs.
954       *    <li class='jc'>{@link Introspectable} - Allows Java public methods to be invoked on the returned POJOs.
955       *    <li class='ja'>{@link Rest#converters()}
956       *    <li class='link'><a class="doclink" href="../../../../index.html#jrs.Converters">Converters</a>
957       * </ul>
958       *
959       * @param beanStore
960       *    The factory used for creating beans and retrieving injected beans.
961       * @param resource
962       *    The REST servlet/bean instance that this context is defined against.
963       * @return A new response converter list sub-builder.
964       */
965      protected RestConverterList.Builder createConverters(BeanStore beanStore, Supplier<?> resource) {
966
967         // Default value.
968         Value<RestConverterList.Builder> v = Value.of(
969            RestConverterList
970               .create(beanStore)
971         );
972
973         // Specify the implementation class if its set as a default.
974         defaultClasses()
975            .get(RestConverterList.class)
976            .ifPresent(x -> v.get().type(x));
977
978         // Replace with bean from bean store.
979         beanStore
980            .getBean(RestConverterList.class)
981            .ifPresent(x->v.get().impl(x));
982
983         // Replace with bean from:  @RestInject(methodScope="foo") public [static] RestConverterList xxx(<args>)
984         beanStore
985            .createMethodFinder(RestConverterList.class)
986            .addBean(RestConverterList.Builder.class, v.get())
987            .find(x -> matches(x))
988            .run(x -> v.get().impl(x));
989
990         return v.get();
991      }
992
993      //-----------------------------------------------------------------------------------------------------------------
994      // guards
995      //-----------------------------------------------------------------------------------------------------------------
996
997      /**
998       * Returns the guard list sub-builder.
999       *
1000       * @return The guard list sub-builder.
1001       */
1002      public RestGuardList.Builder guards() {
1003         if (guards == null)
1004            guards = createGuards(beanStore(), resource());
1005         return guards;
1006      }
1007
1008      /**
1009       * Adds one or more guards to this operation.
1010       *
1011       * <p>
1012       * Equivalent to calling:
1013       * <p class='bjava'>
1014       *    <jv>builder</jv>.guards().append(<jv>value</jv>);
1015       * </p>
1016       *
1017       * @param value The values to add.
1018       * @return This object.
1019       */
1020      @SafeVarargs
1021      public final Builder guards(Class<? extends RestGuard>...value) {
1022         guards().append(value);
1023         return this;
1024      }
1025
1026      /**
1027       * Adds one or more guards to this operation.
1028       *
1029       * <p>
1030       * Equivalent to calling:
1031       * <p class='bjava'>
1032       *    <jv>builder</jv>.guards().append(<jv>value</jv>);
1033       * </p>
1034       *
1035       * @param value The values to add.
1036       * @return This object.
1037       */
1038      public Builder guards(RestGuard...value) {
1039         guards().append(value);
1040         return this;
1041      }
1042
1043      /**
1044       * Instantiates the guard list sub-builder.
1045       *
1046       * <p>
1047       * Instantiates based on the following logic:
1048       * <ul>
1049       *    <li>Looks for guards set via any of the following:
1050       *       <ul>
1051       *          <li>{@link RestOpContext.Builder#guards()}}
1052       *          <li>{@link RestOp#guards()}.
1053       *          <li>{@link Rest#guards()}.
1054       *       </ul>
1055       *    <li>Looks for a static or non-static <c>createGuards()</c> method that returns <c>{@link RestGuard}[]</c> on the
1056       *       resource class with any of the following arguments:
1057       *       <ul>
1058       *          <li>{@link Method} - The Java method this context belongs to.
1059       *          <li>{@link RestContext}
1060       *          <li>{@link BeanStore}
1061       *          <li>Any <a class="doclink" href="../../../../index.html#juneau-rest-server-springboot">injected beans</a>.
1062       *       </ul>
1063       *    <li>Resolves it via the bean store registered in this context.
1064       *    <li>Instantiates a <c>RestGuard[0]</c>.
1065       * </ul>
1066       *
1067       * @param beanStore
1068       *    The factory used for creating beans and retrieving injected beans.
1069       * @param resource
1070       *    The REST servlet/bean instance that this context is defined against.
1071       * @return A new guard list sub-builder.
1072       */
1073      protected RestGuardList.Builder createGuards(BeanStore beanStore, Supplier<?> resource) {
1074
1075         // Default value.
1076         Value<RestGuardList.Builder> v = Value.of(
1077            RestGuardList
1078               .create(beanStore)
1079         );
1080
1081         // Specify the implementation class if its set as a default.
1082         defaultClasses()
1083            .get(RestGuardList.class)
1084            .ifPresent(x -> v.get().type(x));
1085
1086         // Replace with bean from bean store.
1087         beanStore
1088            .getBean(RestGuardList.class)
1089            .ifPresent(x->v.get().impl(x));
1090
1091         // Replace with bean from:  @RestInject(methodScope="foo") public [static] RestGuardList xxx(<args>)
1092         beanStore
1093            .createMethodFinder(RestGuardList.class)
1094            .addBean(RestGuardList.Builder.class, v.get())
1095            .find(x -> matches(x))
1096            .run(x -> v.get().impl(x));
1097
1098         return v.get();
1099      }
1100
1101      RestGuardList getGuards() {
1102         RestGuardList.Builder b = guards();
1103         Set<String> roleGuard = optional(this.roleGuard).orElseGet(()->set());
1104
1105         for (String rg : roleGuard) {
1106            try {
1107               b.append(new RoleBasedRestGuard(rolesDeclared, rg));
1108            } catch (java.text.ParseException e1) {
1109               throw asRuntimeException(e1);
1110            }
1111         }
1112
1113         return guards.build();
1114      }
1115
1116      //-----------------------------------------------------------------------------------------------------------------
1117      // matchers
1118      //-----------------------------------------------------------------------------------------------------------------
1119
1120      /**
1121       * Returns the matcher list sub-builder.
1122       *
1123       * @return The matcher list sub-builder.
1124       */
1125      public RestMatcherList.Builder matchers() {
1126         if (matchers == null)
1127            matchers = createMatchers(beanStore(), resource());
1128         return matchers;
1129      }
1130
1131      /**
1132       * Adds one or more matchers to this operation.
1133       *
1134       * <p>
1135       * Equivalent to calling:
1136       * <p class='bjava'>
1137       *    <jv>builder</jv>.matchers().append(<jv>value</jv>);
1138       * </p>
1139       *
1140       * @param value The values to add.
1141       * @return This object.
1142       */
1143      @SafeVarargs
1144      public final Builder matchers(Class<? extends RestMatcher>...value) {
1145         matchers().append(value);
1146         return this;
1147      }
1148
1149      /**
1150       * Adds one or more matchers to this operation.
1151       *
1152       * <p>
1153       * Equivalent to calling:
1154       * <p class='bjava'>
1155       *    <jv>builder</jv>.matchers().append(<jv>value</jv>);
1156       * </p>
1157       *
1158       * @param value The values to add.
1159       * @return This object.
1160       */
1161      public Builder matchers(RestMatcher...value) {
1162         matchers().append(value);
1163         return this;
1164      }
1165
1166      /**
1167       * Instantiates the matcher list sub-builder.
1168       *
1169       * <p>
1170       * Associates one or more {@link RestMatcher RestMatchers} with the specified method.
1171       *
1172       * <p>
1173       * If multiple matchers are specified, <b>ONE</b> matcher must pass.
1174       * <br>Note that this is different than guards where <b>ALL</b> guards needs to pass.
1175       *
1176       * <h5 class='section'>Notes:</h5><ul>
1177       *    <li class='note'>
1178       *       When defined as a class, the implementation must have one of the following constructors:
1179       *       <ul>
1180       *          <li><code><jk>public</jk> T(RestContext)</code>
1181       *          <li><code><jk>public</jk> T()</code>
1182       *          <li><code><jk>public static</jk> T <jsm>create</jsm>(RestContext)</code>
1183       *          <li><code><jk>public static</jk> T <jsm>create</jsm>()</code>
1184       *       </ul>
1185       *    <li class='note'>
1186       *       Inner classes of the REST resource class are allowed.
1187       * </ul>
1188       *
1189       * <h5 class='section'>See Also:</h5><ul>
1190       *    <li class='ja'>{@link RestOp#matchers()}
1191       *    <li class='ja'>{@link RestGet#matchers()}
1192       *    <li class='ja'>{@link RestPut#matchers()}
1193       *    <li class='ja'>{@link RestPost#matchers()}
1194       *    <li class='ja'>{@link RestDelete#matchers()}
1195       * </ul>
1196       *
1197       * <p>
1198       * Instantiates based on the following logic:
1199       * <ul>
1200       *    <li>Looks for matchers set via any of the following:
1201       *       <ul>
1202       *          <li>{@link RestOp#matchers()}.
1203       *       </ul>
1204       *    <li>Looks for a static or non-static <c>createMatchers()</c> method that returns <c>{@link RestMatcher}[]</c> on the
1205       *       resource class with any of the following arguments:
1206       *       <ul>
1207       *          <li>{@link java.lang.reflect.Method} - The Java method this context belongs to.
1208       *          <li>{@link RestContext}
1209       *          <li>{@link BeanStore}
1210       *          <li>Any <a class="doclink" href="../../../../index.html#juneau-rest-server-springboot">injected beans</a>.
1211       *       </ul>
1212       *    <li>Resolves it via the bean store registered in this context.
1213       *    <li>Instantiates a <c>RestMatcher[0]</c>.
1214       * </ul>
1215       *
1216       * @param beanStore
1217       *    The factory used for creating beans and retrieving injected beans.
1218       * @param resource
1219       *    The REST servlet/bean instance that this context is defined against.
1220       * @return A new matcher list sub-builder.
1221       */
1222      protected RestMatcherList.Builder createMatchers(BeanStore beanStore, Supplier<?> resource) {
1223
1224         // Default value.
1225         Value<RestMatcherList.Builder> v = Value.of(
1226            RestMatcherList
1227               .create(beanStore)
1228         );
1229
1230         // Specify the implementation class if its set as a default.
1231         defaultClasses()
1232            .get(RestMatcherList.class)
1233            .ifPresent(x -> v.get().type(x));
1234
1235         // Replace with bean from bean store.
1236         beanStore
1237            .getBean(RestMatcherList.class)
1238            .ifPresent(x->v.get().impl(x));
1239
1240         // Replace with bean from:  @RestInject(methodScope="foo") public [static] RestMatcherList xxx(<args>)
1241         beanStore
1242            .createMethodFinder(RestMatcherList.class)
1243            .addBean(RestMatcherList.Builder.class, v.get())
1244            .find(x -> matches(x))
1245            .run(x -> v.get().impl(x));
1246
1247         return v.get();
1248      }
1249
1250      RestMatcherList getMatchers(RestContext restContext) {
1251         RestMatcherList.Builder b = matchers();
1252         if (clientVersion != null)
1253            b.append(new ClientVersionMatcher(restContext.getClientVersionHeader(), MethodInfo.of(restMethod)));
1254
1255         return b.build();
1256      }
1257
1258      //-----------------------------------------------------------------------------------------------------------------
1259      // pathMatchers
1260      //-----------------------------------------------------------------------------------------------------------------
1261
1262      /**
1263       * Instantiates the path matchers for this method.
1264       *
1265       * @return The path matchers for this method.
1266       */
1267      protected UrlPathMatcherList getPathMatchers() {
1268
1269         Value<UrlPathMatcherList> v = Value.of(
1270            UrlPathMatcherList.create()
1271         );
1272
1273         if (path != null) {
1274            for (String p : path) {
1275               if (dotAll && ! p.endsWith("/*"))
1276                  p += "/*";
1277               v.get().add(UrlPathMatcher.of(p));
1278            }
1279         }
1280
1281         if (v.get().isEmpty()) {
1282            MethodInfo mi = MethodInfo.of(restMethod);
1283            String p = null;
1284            String httpMethod = null;
1285            if (mi.hasAnnotation(RestGet.class))
1286               httpMethod = "get";
1287            else if (mi.hasAnnotation(RestPut.class))
1288               httpMethod = "put";
1289            else if (mi.hasAnnotation(RestPost.class))
1290               httpMethod = "post";
1291            else if (mi.hasAnnotation(RestDelete.class))
1292               httpMethod = "delete";
1293            else if (mi.hasAnnotation(RestOp.class)) {
1294               Value<String> _httpMethod = Value.empty();
1295               mi.forEachAnnotation(RestOp.class, x -> isNotEmpty(x.method()), x -> _httpMethod.set(x.method()));
1296               httpMethod = _httpMethod.orElse(null);
1297            }
1298
1299            p = HttpUtils.detectHttpPath(restMethod, httpMethod);
1300
1301            if (dotAll && ! p.endsWith("/*"))
1302               p += "/*";
1303
1304            v.get().add(UrlPathMatcher.of(p));
1305         }
1306
1307         // Replace with bean from:  @RestInject(methodScope="foo") public [static] UrlPathMatcherList xxx(<args>)
1308         beanStore
1309            .createMethodFinder(UrlPathMatcherList.class, resource().get())
1310            .addBean(UrlPathMatcherList.class, v.get())
1311            .find(x -> matches(x))
1312            .run(x -> v.set(x));
1313
1314         return v.get();
1315      }
1316
1317      /**
1318       * When enabled, append <js>"/*"</js> to path patterns if not already present.
1319       *
1320       * @return This object.
1321       */
1322      public Builder dotAll() {
1323         dotAll = true;
1324         return this;
1325      }
1326
1327      //-----------------------------------------------------------------------------------------------------------------
1328      // defaultRequestHeaders
1329      //-----------------------------------------------------------------------------------------------------------------
1330
1331      /**
1332       * Returns the default request headers.
1333       *
1334       * @return The default request headers.
1335       */
1336      public HeaderList defaultRequestHeaders() {
1337         if (defaultRequestHeaders == null)
1338            defaultRequestHeaders = createDefaultRequestHeaders(beanStore(), parent, resource());
1339         return defaultRequestHeaders;
1340      }
1341
1342      /**
1343       * Adds one or more default request headers to this operation.
1344       *
1345       * <p>
1346       * Equivalent to calling:
1347       * <p class='bjava'>
1348       *    <jv>builder</jv>.defaultRequestHeaders().append(<jv>value</jv>);
1349       * </p>
1350       *
1351       * @param value The values to add.
1352       * @return This object.
1353       */
1354      public Builder defaultRequestHeaders(org.apache.http.Header...value) {
1355         defaultRequestHeaders().append(value);
1356         return this;
1357      }
1358
1359      /**
1360       * Instantiates the default request headers.
1361       *
1362       * @param beanStore
1363       *    The factory used for creating beans and retrieving injected beans.
1364       * @param parent
1365       *    The builder for the REST resource class.
1366       * @param resource
1367       *    The REST servlet/bean instance that this context is defined against.
1368       * @return A new default request headers sub-builder.
1369       */
1370      protected HeaderList createDefaultRequestHeaders(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1371
1372         Value<HeaderList> v = Value.of(
1373            parent.defaultRequestHeaders().copy()
1374         );
1375
1376         // Replace with bean from:  @RestInject(name="defaultRequestHeaders",methodScope="foo") public [static] HeaderList xxx(<args>)
1377         BeanStore
1378            .of(beanStore, resource)
1379            .addBean(HeaderList.class, v.get())
1380            .createMethodFinder(HeaderList.class, resource)
1381            .find(x -> matches(x, "defaultRequestHeaders"))
1382            .run(x -> v.set(x));
1383
1384         return v.get();
1385      }
1386
1387      //-----------------------------------------------------------------------------------------------------------------
1388      // defaultResponseHeaders
1389      //-----------------------------------------------------------------------------------------------------------------
1390
1391      /**
1392       * Returns the default response headers.
1393       *
1394       * @return The default response headers.
1395       */
1396      public HeaderList defaultResponseHeaders() {
1397         if (defaultResponseHeaders == null)
1398            defaultResponseHeaders = createDefaultResponseHeaders(beanStore(), parent, resource());
1399         return defaultResponseHeaders;
1400      }
1401
1402      /**
1403       * Adds one or more default response headers to this operation.
1404       *
1405       * <p>
1406       * Equivalent to calling:
1407       * <p class='bjava'>
1408       *    <jv>builder</jv>.defaultResponseHeaders().append(<jv>value</jv>);
1409       * </p>
1410       *
1411       * @param value The values to add.
1412       * @return This object.
1413       */
1414      public Builder defaultResponseHeaders(org.apache.http.Header...value) {
1415         defaultResponseHeaders().append(value);
1416         return this;
1417      }
1418
1419      /**
1420       * Instantiates the default response headers.
1421       *
1422       * @param beanStore
1423       *    The factory used for creating beans and retrieving injected beans.
1424       * @param parent
1425       *    The builder for the REST resource class.
1426       * @param resource
1427       *    The REST servlet/bean instance that this context is defined against.
1428       * @return A new default response headers sub-builder.
1429       */
1430      protected HeaderList createDefaultResponseHeaders(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1431
1432         Value<HeaderList> v = Value.of(
1433            parent.defaultResponseHeaders().copy()
1434         );
1435
1436         // Replace with bean from:  @RestInject(name="defaultResponseHeaders",methodScope="foo") public [static] HeaderList xxx(<args>)
1437         BeanStore
1438            .of(beanStore, resource)
1439            .addBean(HeaderList.class, v.get())
1440            .createMethodFinder(HeaderList.class, resource)
1441            .find(x -> matches(x, "defaultResponseHeaders"))
1442            .run(x -> v.set(x));
1443
1444         return v.get();
1445      }
1446
1447      //-----------------------------------------------------------------------------------------------------------------
1448      // defaultRequestAttributes
1449      //-----------------------------------------------------------------------------------------------------------------
1450
1451      /**
1452       * Returns the default request attributes sub-builder.
1453       *
1454       * @return The default request attributes sub-builder.
1455       */
1456      public NamedAttributeMap defaultRequestAttributes() {
1457         if (defaultRequestAttributes == null)
1458            defaultRequestAttributes = createDefaultRequestAttributes(beanStore(), parent, resource());
1459         return defaultRequestAttributes;
1460      }
1461
1462      /**
1463       * Adds one or more default request attributes to this operation.
1464       *
1465       * <p>
1466       * Equivalent to calling:
1467       * <p class='bjava'>
1468       *    <jv>builder</jv>.defaultRequestAttributes().append(<jv>value</jv>);
1469       * </p>
1470       *
1471       * @param value The values to add.
1472       * @return This object.
1473       */
1474      public Builder defaultRequestAttributes(NamedAttribute...value) {
1475         defaultRequestAttributes().add(value);
1476         return this;
1477      }
1478
1479      /**
1480       * Instantiates the default request attributes sub-builder.
1481       *
1482       * @param beanStore
1483       *    The factory used for creating beans and retrieving injected beans.
1484       * @param parent
1485       *    The builder for the REST resource class.
1486       * @param resource
1487       *    The REST servlet/bean instance that this context is defined against.
1488       * @return A new default request attributes sub-builder.
1489       */
1490      protected NamedAttributeMap createDefaultRequestAttributes(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1491
1492         Value<NamedAttributeMap> v = Value.of(
1493            parent.defaultRequestAttributes().copy()
1494         );
1495
1496         // Replace with bean from:  @RestInject(name="defaultRequestAttributes",methodScope="foo") public [static] NamedAttributeMap xxx(<args>)
1497         BeanStore
1498            .of(beanStore, resource)
1499            .addBean(NamedAttributeMap.class, v.get())
1500            .createMethodFinder(NamedAttributeMap.class, resource)
1501            .find(x -> matches(x, "defaultRequestAttributes"))
1502            .run(x -> v.set(x));
1503
1504         return v.get();
1505      }
1506
1507      //-----------------------------------------------------------------------------------------------------------------
1508      // defaultRequestQuery
1509      //-----------------------------------------------------------------------------------------------------------------
1510
1511      /**
1512       * Returns the default request query data.
1513       *
1514       * @return The default request query data.
1515       */
1516      public PartList defaultRequestQueryData() {
1517         if (defaultRequestQueryData == null)
1518            defaultRequestQueryData = createDefaultRequestQueryData(beanStore(), parent, resource());
1519         return defaultRequestQueryData;
1520      }
1521
1522      /**
1523       * Adds one or more default request query data to this operation.
1524       *
1525       * <p>
1526       * Equivalent to calling:
1527       * <p class='bjava'>
1528       *    <jv>builder</jv>.defaultRequestQueryData().append(<jv>value</jv>);
1529       * </p>
1530       *
1531       * @param value The values to add.
1532       * @return This object.
1533       */
1534      public Builder defaultRequestQueryData(NameValuePair...value) {
1535         defaultRequestQueryData().append(value);
1536         return this;
1537      }
1538
1539      /**
1540       * Instantiates the default request query data.
1541       *
1542       * @param beanStore
1543       *    The factory used for creating beans and retrieving injected beans.
1544       * @param parent
1545       *    The builder for the REST resource class.
1546       * @param resource
1547       *    The REST servlet/bean instance that this context is defined against.
1548       * @return A new default request query data sub-builder.
1549       */
1550      protected PartList createDefaultRequestQueryData(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1551
1552         Value<PartList> v = Value.of(
1553            PartList.create()
1554         );
1555
1556         // Replace with bean from:  @RestInject(name="defaultRequestQueryData",methodScope="foo") public [static] PartList xxx(<args>)
1557         BeanStore
1558            .of(beanStore, resource)
1559            .addBean(PartList.class, v.get())
1560            .createMethodFinder(PartList.class, resource)
1561            .find(x -> matches(x, "defaultRequestQueryData"))
1562            .run(x -> v.set(x));
1563
1564         return v.get();
1565      }
1566
1567      //-----------------------------------------------------------------------------------------------------------------
1568      // defaultRequestFormData
1569      //-----------------------------------------------------------------------------------------------------------------
1570
1571      /**
1572       * Returns the default request form data.
1573       *
1574       * @return The default request form data.
1575       */
1576      public PartList defaultRequestFormData() {
1577         if (defaultRequestFormData == null)
1578            defaultRequestFormData = createDefaultRequestFormData(beanStore(), parent, resource());
1579         return defaultRequestFormData;
1580      }
1581
1582      /**
1583       * Adds one or more default request form data to this operation.
1584       *
1585       * <p>
1586       * Equivalent to calling:
1587       * <p class='bjava'>
1588       *    <jv>builder</jv>.defaultRequestFormData().append(<jv>value</jv>);
1589       * </p>
1590       *
1591       * @param value The values to add.
1592       * @return This object.
1593       */
1594      public Builder defaultRequestFormData(NameValuePair...value) {
1595         defaultRequestFormData().append(value);
1596         return this;
1597      }
1598
1599      /**
1600       * Instantiates the default request form data.
1601       *
1602       * @param beanStore
1603       *    The factory used for creating beans and retrieving injected beans.
1604       * @param parent
1605       *    The builder for the REST resource class.
1606       * @param resource
1607       *    The REST servlet/bean instance that this context is defined against.
1608       * @return A new default request form data sub-builder.
1609       */
1610      protected PartList createDefaultRequestFormData(BeanStore beanStore, RestContext.Builder parent, Supplier<?> resource) {
1611
1612         Value<PartList> v = Value.of(
1613            PartList.create()
1614         );
1615
1616         // Replace with bean from:  @RestInject(name="defaultRequestFormData",methodScope="foo") public [static] PartList xxx(<args>)
1617         BeanStore
1618            .of(beanStore, resource)
1619            .addBean(PartList.class, v.get())
1620            .createMethodFinder(PartList.class, resource)
1621            .find(x -> matches(x, "defaultRequestFormData"))
1622            .run(x -> v.set(x));
1623
1624         return v.get();
1625      }
1626
1627      //-----------------------------------------------------------------------------------------------------------------
1628      // Parameter annotations
1629      //-----------------------------------------------------------------------------------------------------------------
1630
1631      /**
1632       * Handles processing of any annotations on parameters.
1633       *
1634       * <p>
1635       * This includes: {@link Header}, {@link Query}, {@link FormData}.
1636       */
1637      protected void processParameterAnnotations() {
1638         for (Annotation[] aa : restMethod.getParameterAnnotations()) {
1639
1640            String def = null;
1641            for (Annotation a : aa) {
1642               if (a instanceof Schema) {
1643                  Schema s = (Schema)a;
1644                  def = joinnlFirstNonEmptyArray(s._default(), s.df());
1645               }
1646            }
1647
1648            for (Annotation a : aa) {
1649               if (a instanceof Header) {
1650                  Header h = (Header)a;
1651                  if (def != null) {
1652                     try {
1653                        defaultRequestHeaders().set(basicHeader(firstNonEmpty(h.name(), h.value()), parseAnything(def)));
1654                     } catch (ParseException e) {
1655                        throw new ConfigException(e, "Malformed @Header annotation");
1656                     }
1657                  }
1658               }
1659               if (a instanceof Query) {
1660                  Query h = (Query)a;
1661                  if (def != null) {
1662                     try {
1663                        defaultRequestQueryData().setDefault(basicPart(firstNonEmpty(h.name(), h.value()), parseAnything(def)));
1664                     } catch (ParseException e) {
1665                        throw new ConfigException(e, "Malformed @Query annotation");
1666                     }
1667                  }
1668               }
1669               if (a instanceof FormData) {
1670                  FormData h = (FormData)a;
1671                  if (def != null) {
1672                     try {
1673                        defaultRequestFormData().setDefault(basicPart(firstNonEmpty(h.name(), h.value()), parseAnything(def)));
1674                     } catch (ParseException e) {
1675                        throw new ConfigException(e, "Malformed @FormData annotation");
1676                     }
1677                  }
1678               }
1679            }
1680         }
1681      }
1682
1683      //----------------------------------------------------------------------------------------------------
1684      // Properties
1685      //----------------------------------------------------------------------------------------------------
1686
1687      /**
1688       * Client version pattern matcher.
1689       *
1690       * <p>
1691       * Specifies whether this method can be called based on the client version.
1692       *
1693       * <p>
1694       * The client version is identified via the HTTP request header identified by
1695       * {@link Rest#clientVersionHeader() @Rest(clientVersionHeader)} which by default is <js>"Client-Version"</js>.
1696       *
1697       * <p>
1698       * This is a specialized kind of {@link RestMatcher} that allows you to invoke different Java methods for the same
1699       * method/path based on the client version.
1700       *
1701       * <p>
1702       * The format of the client version range is similar to that of OSGi versions.
1703       *
1704       * <p>
1705       * In the following example, the Java methods are mapped to the same HTTP method and URL <js>"/foobar"</js>.
1706       * <p class='bjava'>
1707       *    <jc>// Call this method if Client-Version is at least 2.0.
1708       *    // Note that this also matches 2.0.1.</jc>
1709       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
1710       *    <jk>public</jk> Object method1()  {...}
1711       *
1712       *    <jc>// Call this method if Client-Version is at least 1.1, but less than 2.0.</jc>
1713       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
1714       *    <jk>public</jk> Object method2()  {...}
1715       *
1716       *    <jc>// Call this method if Client-Version is less than 1.1.</jc>
1717       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
1718       *    <jk>public</jk> Object method3()  {...}
1719       * </p>
1720       *
1721       * <p>
1722       * It's common to combine the client version with transforms that will convert new POJOs into older POJOs for
1723       * backwards compatibility.
1724       * <p class='bjava'>
1725       *    <jc>// Call this method if Client-Version is at least 2.0.</jc>
1726       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"2.0"</js>)
1727       *    <jk>public</jk> NewPojo newMethod()  {...}
1728       *
1729       *    <jc>// Call this method if Client-Version is at least 1.1, but less than 2.0.</jc>
1730       *    <ja>@RestGet</ja>(path=<js>"/foobar"</js>, clientVersion=<js>"[1.1,2.0)"</js>)
1731       *    <ja>@BeanConfig(swaps=NewToOldSwap.<jk>class</jk>)
1732       *    <jk>public</jk> NewPojo oldMethod() {
1733       *       <jk>return</jk> newMethod();
1734       *    }
1735       *
1736       * <p>
1737       * Note that in the previous example, we're returning the exact same POJO, but using a transform to convert it into
1738       * an older form.
1739       * The old method could also just return back a completely different object.
1740       * The range can be any of the following:
1741       * <ul>
1742       *    <li><js>"[0,1.0)"</js> = Less than 1.0.  1.0 and 1.0.0 does not match.
1743       *    <li><js>"[0,1.0]"</js> = Less than or equal to 1.0.  Note that 1.0.1 will match.
1744       *    <li><js>"1.0"</js> = At least 1.0.  1.0 and 2.0 will match.
1745       * </ul>
1746       *
1747       * <h5 class='section'>See Also:</h5><ul>
1748       *    <li class='ja'>{@link RestOp#clientVersion}
1749       *    <li class='ja'>{@link RestGet#clientVersion}
1750       *    <li class='ja'>{@link RestPut#clientVersion}
1751       *    <li class='ja'>{@link RestPost#clientVersion}
1752       *    <li class='ja'>{@link RestDelete#clientVersion}
1753       *    <li class='jm'>{@link RestContext.Builder#clientVersionHeader(String)}
1754       * </ul>
1755       *
1756       * @param value The new value for this setting.
1757       * @return This object.
1758       */
1759      @FluentSetter
1760      public Builder clientVersion(String value) {
1761         clientVersion = value;
1762         return this;
1763      }
1764
1765      /**
1766       * Debug mode.
1767       *
1768       * <p>
1769       * Enables the following:
1770       * <ul class='spaced-list'>
1771       *    <li>
1772       *       HTTP request/response bodies are cached in memory for logging purposes.
1773       * </ul>
1774       *
1775       * <p>
1776       * If not sppecified, the debug enablement is inherited from the class context.
1777       *
1778       * @param value The new value for this setting.
1779       * @return This object.
1780       */
1781      @FluentSetter
1782      public Builder debug(Enablement value) {
1783         debug = value;
1784         return this;
1785      }
1786
1787      /**
1788       * Default character encoding.
1789       *
1790       * <p>
1791       * The default character encoding for the request and response if not specified on the request.
1792       *
1793       * <p>
1794       * This overrides the value defined on the {@link RestContext}.
1795       *
1796       * <h5 class='section'>See Also:</h5><ul>
1797       *    <li class='jm'>{@link RestContext.Builder#defaultCharset(Charset)}
1798       *    <li class='ja'>{@link Rest#defaultCharset}
1799       *    <li class='ja'>{@link RestOp#defaultCharset}
1800       * </ul>
1801       *
1802       * @param value
1803       *    The new value for this setting.
1804       *    <br>The default is the first value found:
1805       *    <ul>
1806       *       <li>System property <js>"RestContext.defaultCharset"
1807       *       <li>Environment variable <js>"RESTCONTEXT_defaultCharset"
1808       *       <li><js>"utf-8"</js>
1809       *    </ul>
1810       * @return This object.
1811       */
1812      @FluentSetter
1813      public Builder defaultCharset(Charset value) {
1814         defaultCharset = value;
1815         return this;
1816      }
1817
1818      /**
1819       * HTTP method name.
1820       *
1821       * <p>
1822       * Typically <js>"GET"</js>, <js>"PUT"</js>, <js>"POST"</js>, <js>"DELETE"</js>, or <js>"OPTIONS"</js>.
1823       *
1824       * <p>
1825       * Method names are case-insensitive (always folded to upper-case).
1826       *
1827       * <p>
1828       * Note that you can use {@link org.apache.juneau.http.HttpMethod} for constant values.
1829       *
1830       * <p>
1831       * Besides the standard HTTP method names, the following can also be specified:
1832       * <ul class='spaced-list'>
1833       *    <li>
1834       *       <js>"*"</js>
1835       *       - Denotes any method.
1836       *       <br>Use this if you want to capture any HTTP methods in a single Java method.
1837       *       <br>The {@link org.apache.juneau.rest.annotation.Method @Method} annotation and/or {@link RestRequest#getMethod()} method can be used to
1838       *       distinguish the actual HTTP method name.
1839       *    <li>
1840       *       <js>""</js>
1841       *       - Auto-detect.
1842       *       <br>The method name is determined based on the Java method name.
1843       *       <br>For example, if the method is <c>doPost(...)</c>, then the method name is automatically detected
1844       *       as <js>"POST"</js>.
1845       *       <br>Otherwise, defaults to <js>"GET"</js>.
1846       *    <li>
1847       *       <js>"RRPC"</js>
1848       *       - Remote-proxy interface.
1849       *       <br>This denotes a Java method that returns an object (usually an interface, often annotated with the
1850       *       {@link Remote @Remote} annotation) to be used as a remote proxy using
1851       *       <c>RestClient.getRemoteInterface(Class&lt;T&gt; interfaceClass, String url)</c>.
1852       *       <br>This allows you to construct client-side interface proxies using REST as a transport medium.
1853       *       <br>Conceptually, this is simply a fancy <c>POST</c> against the url <js>"/{path}/{javaMethodName}"</js>
1854       *       where the arguments are marshalled from the client to the server as an HTTP content containing an array of
1855       *       objects, passed to the method as arguments, and then the resulting object is marshalled back to the client.
1856       *    <li>
1857       *       Anything else
1858       *       - Overloaded non-HTTP-standard names that are passed in through a <c>&amp;method=methodName</c> URL
1859       *       parameter.
1860       * </ul>
1861       *
1862       * <h5 class='section'>See Also:</h5><ul>
1863       *    <li class='ja'>{@link RestOp#method()}
1864       *    <li class='ja'>{@link RestGet}
1865       *    <li class='ja'>{@link RestPut}
1866       *    <li class='ja'>{@link RestPost}
1867       *    <li class='ja'>{@link RestDelete}
1868       * </ul>
1869       *
1870       * @param value The new value for this setting.
1871       * @return This object.
1872       */
1873      @FluentSetter
1874      public Builder httpMethod(String value) {
1875         this.httpMethod = value;
1876         return this;
1877      }
1878
1879      /**
1880       * The maximum allowed input size (in bytes) on HTTP requests.
1881       *
1882       * <p>
1883       * Useful for alleviating DoS attacks by throwing an exception when too much input is received instead of resulting
1884       * in out-of-memory errors which could affect system stability.
1885       *
1886       * <h5 class='section'>Example:</h5>
1887       * <p class='bjava'>
1888       *    <jc>// Option #1 - Defined via annotation resolving to a config file setting with default value.</jc>
1889       *    <ja>@Rest</ja>(maxInput=<js>"$C{REST/maxInput,10M}"</js>)
1890       *    <jk>public class</jk> MyResource {
1891       *
1892       *       <jc>// Option #2 - Defined via builder passed in through resource constructor.</jc>
1893       *       <jk>public</jk> MyResource(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
1894       *
1895       *          <jc>// Using method on builder.</jc>
1896       *          <jv>builder</jv>.maxInput(<js>"10M"</js>);
1897       *       }
1898       *
1899       *       <jc>// Option #3 - Defined via builder passed in through init method.</jc>
1900       *       <ja>@RestInit</ja>
1901       *       <jk>public void</jk> init(RestContext.Builder <jv>builder</jv>) <jk>throws</jk> Exception {
1902       *          <jv>builder</jv>.maxInput(<js>"10M"</js>);
1903       *       }
1904       *
1905       *       <jc>// Override at the method level.</jc>
1906       *       <ja>@RestPost</ja>(maxInput=<js>"10M"</js>)
1907       *       <jk>public</jk> Object myMethod() {...}
1908       *    }
1909       * </p>
1910       *
1911       * <h5 class='section'>Notes:</h5><ul>
1912       *    <li class='note'>
1913       *       String value that gets resolved to a <jk>long</jk>.
1914       *    <li class='note'>
1915       *       Can be suffixed with any of the following representing kilobytes, megabytes, and gigabytes:
1916       *       <js>'K'</js>, <js>'M'</js>, <js>'G'</js>.
1917       *    <li class='note'>
1918       *       A value of <js>"-1"</js> can be used to represent no limit.
1919       * </ul>
1920       *
1921       * <h5 class='section'>See Also:</h5><ul>
1922       *    <li class='ja'>{@link Rest#maxInput}
1923       *    <li class='ja'>{@link RestOp#maxInput}
1924       *    <li class='jm'>{@link RestOpContext.Builder#maxInput(String)}
1925       * </ul>
1926       *
1927       * @param value
1928       *    The new value for this setting.
1929       *    <br>The default is the first value found:
1930       *    <ul>
1931       *       <li>System property <js>"RestContext.maxInput"
1932       *       <li>Environment variable <js>"RESTCONTEXT_MAXINPUT"
1933       *       <li><js>"100M"</js>
1934       *    </ul>
1935       *    <br>The default is <js>"100M"</js>.
1936       * @return This object.
1937       */
1938      @FluentSetter
1939      public Builder maxInput(String value) {
1940         maxInput = StringUtils.parseLongWithSuffix(value);
1941         return this;
1942      }
1943
1944      /**
1945       * Resource method paths.
1946       *
1947       * <p>
1948       * Identifies the URL subpath relative to the servlet class.
1949       *
1950       * <p>
1951       * <h5 class='section'>Notes:</h5><ul>
1952       *    <li class='note'>
1953       *       This method is only applicable for Java methods.
1954       *    <li class='note'>
1955       *       Slashes are trimmed from the path ends.
1956       *       <br>As a convention, you may want to start your path with <js>'/'</js> simple because it make it easier to read.
1957       * </ul>
1958       *
1959       * @param values The new values for this setting.
1960       * @return This object.
1961       */
1962      @FluentSetter
1963      public Builder path(String...values) {
1964         path = prependAll(path, values);
1965         return this;
1966      }
1967
1968      /**
1969       * Supported accept media types.
1970       *
1971       * <p>
1972       * Overrides the media types inferred from the serializers that identify what media types can be produced by the resource.
1973       * <br>An example where this might be useful if you have serializers registered that handle media types that you
1974       * don't want exposed in the Swagger documentation.
1975       *
1976       * <p>
1977       * This affects the returned values from the following:
1978       * <ul class='javatree'>
1979       *    <li class='jm'>{@link RestContext#getProduces() RestContext.getProduces()}
1980       *    <li class='jm'>{@link SwaggerProvider#getSwagger(RestContext,Locale)} - Affects produces field.
1981       * </ul>
1982       *
1983       * <h5 class='section'>See Also:</h5><ul>
1984       *    <li class='ja'>{@link Rest#produces}
1985       *    <li class='ja'>{@link RestOp#produces}
1986       *    <li class='ja'>{@link RestGet#produces}
1987       *    <li class='ja'>{@link RestPut#produces}
1988       *    <li class='ja'>{@link RestPost#produces}
1989       * </ul>
1990       *
1991       * @param values The values to add to this setting.
1992       * @return This object.
1993       */
1994      @FluentSetter
1995      public Builder produces(MediaType...values) {
1996         produces = addAll(produces, values);
1997         return this;
1998      }
1999
2000      /**
2001       * Declared roles.
2002       *
2003       * <p>
2004       * A comma-delimited list of all possible user roles.
2005       *
2006       * <p>
2007       * Used in conjunction with {@link RestOpContext.Builder#roleGuard(String)} is used with patterns.
2008       *
2009       * <h5 class='section'>Example:</h5>
2010       * <p class='bjava'>
2011       *    <ja>@Rest</ja>(
2012       *       rolesDeclared=<js>"ROLE_ADMIN,ROLE_READ_WRITE,ROLE_READ_ONLY,ROLE_SPECIAL"</js>,
2013       *       roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
2014       *    )
2015       *    <jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {
2016       *       ...
2017       *    }
2018       * </p>
2019       *
2020       * <h5 class='section'>See Also:</h5><ul>
2021       *    <li class='ja'>{@link Rest#rolesDeclared}
2022       * </ul>
2023       *
2024       * @param values The values to add to this setting.
2025       * @return This object.
2026       */
2027      @FluentSetter
2028      public Builder rolesDeclared(String...values) {
2029         rolesDeclared = addAll(rolesDeclared, values);
2030         return this;
2031      }
2032
2033      /**
2034       * Role guard.
2035       *
2036       * <p>
2037       * An expression defining if a user with the specified roles are allowed to access methods on this class.
2038       *
2039       * <h5 class='section'>Example:</h5>
2040       * <p class='bjava'>
2041       *    <ja>@Rest</ja>(
2042       *       path=<js>"/foo"</js>,
2043       *       roleGuard=<js>"ROLE_ADMIN || (ROLE_READ_WRITE &amp;&amp; ROLE_SPECIAL)"</js>
2044       *    )
2045       *    <jk>public class</jk> MyResource <jk>extends</jk> BasicRestServlet {
2046       *       ...
2047       *    }
2048       * </p>
2049       *
2050       * <h5 class='section'>Notes:</h5><ul>
2051       *    <li class='note'>
2052       *       Supports any of the following expression constructs:
2053       *       <ul>
2054       *          <li><js>"foo"</js> - Single arguments.
2055       *          <li><js>"foo,bar,baz"</js> - Multiple OR'ed arguments.
2056       *          <li><js>"foo | bar | bqz"</js> - Multiple OR'ed arguments, pipe syntax.
2057       *          <li><js>"foo || bar || bqz"</js> - Multiple OR'ed arguments, Java-OR syntax.
2058       *          <li><js>"fo*"</js> - Patterns including <js>'*'</js> and <js>'?'</js>.
2059       *          <li><js>"fo* &amp; *oo"</js> - Multiple AND'ed arguments, ampersand syntax.
2060       *          <li><js>"fo* &amp;&amp; *oo"</js> - Multiple AND'ed arguments, Java-AND syntax.
2061       *          <li><js>"fo* || (*oo || bar)"</js> - Parenthesis.
2062       *       </ul>
2063       *    <li class='note'>
2064       *       AND operations take precedence over OR operations (as expected).
2065       *    <li class='note'>
2066       *       Whitespace is ignored.
2067       *    <li class='note'>
2068       *       <jk>null</jk> or empty expressions always match as <jk>false</jk>.
2069       *    <li class='note'>
2070       *       If patterns are used, you must specify the list of declared roles using {@link Rest#rolesDeclared()} or {@link RestOpContext.Builder#rolesDeclared(String...)}.
2071       *    <li class='note'>
2072       *       Supports <a class="doclink" href="../../../../index.html#jrs.SvlVariables">SVL Variables</a>
2073       *       (e.g. <js>"$L{my.localized.variable}"</js>).
2074       * </ul>
2075       *
2076       * @param value The values to add to this setting.
2077       * @return This object.
2078       */
2079      @FluentSetter
2080      public Builder roleGuard(String value) {
2081         if (roleGuard == null)
2082            roleGuard = set(value);
2083         else
2084            roleGuard.add(value);
2085         return this;
2086      }
2087
2088      /**
2089       * Supported content media types.
2090       *
2091       * <p>
2092       * Overrides the media types inferred from the parsers that identify what media types can be consumed by the resource.
2093       * <br>An example where this might be useful if you have parsers registered that handle media types that you
2094       * don't want exposed in the Swagger documentation.
2095       *
2096       * <p>
2097       * This affects the returned values from the following:
2098       * <ul class='javatree'>
2099       *    <li class='jm'>{@link RestContext#getConsumes() RestContext.getConsumes()}
2100       * </ul>
2101       *
2102       * <h5 class='section'>See Also:</h5><ul>
2103       *    <li class='ja'>{@link Rest#consumes}
2104       *    <li class='ja'>{@link RestOp#consumes}
2105       *    <li class='ja'>{@link RestPut#consumes}
2106       *    <li class='ja'>{@link RestPost#consumes}
2107       * </ul>
2108       *
2109       * @param values The values to add to this setting.
2110       * @return This object.
2111       */
2112      @FluentSetter
2113      public Builder consumes(MediaType...values) {
2114         consumes = addAll(consumes, values);
2115         return this;
2116      }
2117
2118      // <FluentSetters>
2119
2120      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2121      public Builder annotations(Annotation...values) {
2122         super.annotations(values);
2123         return this;
2124      }
2125
2126      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2127      public Builder apply(AnnotationWorkList work) {
2128         super.apply(work);
2129         return this;
2130      }
2131
2132      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2133      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
2134         super.applyAnnotations(fromClasses);
2135         return this;
2136      }
2137
2138      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2139      public Builder applyAnnotations(Method...fromMethods) {
2140         super.applyAnnotations(fromMethods);
2141         return this;
2142      }
2143
2144      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2145      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
2146         super.cache(value);
2147         return this;
2148      }
2149
2150      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2151      public Builder debug() {
2152         super.debug();
2153         return this;
2154      }
2155
2156      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2157      public Builder debug(boolean value) {
2158         super.debug(value);
2159         return this;
2160      }
2161
2162      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2163      public Builder impl(Context value) {
2164         super.impl(value);
2165         return this;
2166      }
2167
2168      @Override /* GENERATED - org.apache.juneau.Context.Builder */
2169      public Builder type(Class<? extends org.apache.juneau.Context> value) {
2170         super.type(value);
2171         return this;
2172      }
2173
2174      // </FluentSetters>
2175
2176      //-----------------------------------------------------------------------------------------------------------------
2177      // Helper methods.
2178      //-----------------------------------------------------------------------------------------------------------------
2179
2180      private boolean matches(MethodInfo annotated) {
2181         RestInject a = annotated.getAnnotation(RestInject.class);
2182         if (a != null) {
2183            for (String n : a.methodScope()) {
2184               if ("*".equals(n))
2185                  return true;
2186               if (restMethod.getName().equals(n))
2187                  return true;
2188            }
2189         }
2190         return false;
2191      }
2192
2193      private boolean matches(MethodInfo annotated, String beanName) {
2194         RestInject a = annotated.getAnnotation(RestInject.class);
2195         if (a != null) {
2196            if (! a.name().equals(beanName))
2197               return false;
2198            for (String n : a.methodScope()) {
2199               if ("*".equals(n))
2200                  return true;
2201               if (restMethod.getName().equals(n))
2202                  return true;
2203            }
2204         }
2205         return false;
2206      }
2207
2208      private String joinnlFirstNonEmptyArray(String[]...s) {
2209         for (String[] ss : s)
2210            if (ss.length > 0)
2211               return joinnl(ss);
2212         return null;
2213      }
2214
2215   }
2216
2217   //-------------------------------------------------------------------------------------------------------------------
2218   // Instance
2219   //-------------------------------------------------------------------------------------------------------------------
2220
2221   private final String httpMethod;
2222   private final UrlPathMatcher[] pathMatchers;
2223   private final RestGuard[] guards;
2224   private final RestMatcher[] requiredMatchers, optionalMatchers;
2225   private final RestConverter[] converters;
2226   private final RestContext context;
2227   private final Method method;
2228   private final RestOpInvoker methodInvoker;
2229   private final RestOpInvoker[]
2230      preCallMethods,
2231      postCallMethods;
2232   private final MethodInfo mi;
2233   private final BeanContext beanContext;
2234   private final SerializerSet serializers;
2235   private final ParserSet parsers;
2236   private final EncoderSet encoders;
2237   private final HttpPartSerializer partSerializer;
2238   private final HttpPartParser partParser;
2239   private final JsonSchemaGenerator jsonSchemaGenerator;
2240   private final HeaderList defaultRequestHeaders, defaultResponseHeaders;
2241   private final PartList defaultRequestQueryData, defaultRequestFormData;
2242   private final NamedAttributeMap defaultRequestAttributes;
2243   private final Charset defaultCharset;
2244   private final long maxInput;
2245   private final List<MediaType>
2246      supportedAcceptTypes,
2247      supportedContentTypes;
2248   private final CallLogger callLogger;
2249
2250   private final Map<Class<?>,ResponseBeanMeta> responseBeanMetas = new ConcurrentHashMap<>();
2251   private final Map<Class<?>,ResponsePartMeta> headerPartMetas = new ConcurrentHashMap<>();
2252   private final ResponseBeanMeta responseMeta;
2253   private final int hierarchyDepth;
2254   private final DebugEnablement debug;
2255
2256   /**
2257    * Context constructor.
2258    *
2259    * @param builder The builder for this object.
2260    * @throws ServletException If context could not be created.
2261    */
2262   protected RestOpContext(Builder builder) throws ServletException {
2263      super(builder);
2264
2265      try {
2266         context = builder.restContext;
2267         method = builder.restMethod;
2268
2269         if (builder.debug == null)
2270            debug = context.getDebugEnablement();
2271         else
2272            debug = DebugEnablement.create(context.getBeanStore()).enable(builder.debug, "*").build();
2273
2274         mi = MethodInfo.of(method).accessible();
2275         Object r = context.getResource();
2276
2277         BeanStore bs = BeanStore.of(context.getRootBeanStore(), r)
2278            .addBean(RestOpContext.class, this)
2279            .addBean(Method.class, method)
2280            .addBean(AnnotationWorkList.class, builder.getApplied());
2281         bs.addBean(BeanStore.class, bs);
2282
2283         beanContext = bs.add(BeanContext.class, builder.getBeanContext().orElse(context.getBeanContext()));
2284         encoders = bs.add(EncoderSet.class, builder.getEncoders().orElse(context.getEncoders()));
2285         serializers = bs.add(SerializerSet.class, builder.getSerializers().orElse(context.getSerializers()));
2286         parsers = bs.add(ParserSet.class, builder.getParsers().orElse(context.getParsers()));
2287         partSerializer = bs.add(HttpPartSerializer.class, builder.getPartSerializer().orElse(context.getPartSerializer()));
2288         partParser = bs.add(HttpPartParser.class, builder.getPartParser().orElse(context.getPartParser()));
2289         jsonSchemaGenerator = bs.add(JsonSchemaGenerator.class, builder.getJsonSchemaGenerator().orElse(context.getJsonSchemaGenerator()));
2290         converters = bs.add(RestConverter[].class, builder.converters().build().asArray());
2291         guards = bs.add(RestGuard[].class, builder.getGuards().asArray());
2292
2293         RestMatcherList matchers = builder.getMatchers(context);
2294         optionalMatchers = matchers.getOptionalEntries();
2295         requiredMatchers = matchers.getRequiredEntries();
2296
2297         pathMatchers = bs.add(UrlPathMatcher[].class, builder.getPathMatchers().asArray());
2298         bs.addBean(UrlPathMatcher.class, pathMatchers.length > 0 ? pathMatchers[0] : null);
2299
2300         supportedAcceptTypes = unmodifiable(builder.produces != null ? builder.produces : serializers.getSupportedMediaTypes());
2301         supportedContentTypes = unmodifiable(builder.consumes != null ? builder.consumes : parsers.getSupportedMediaTypes());
2302
2303         defaultRequestHeaders = builder.defaultRequestHeaders();
2304         defaultResponseHeaders = builder.defaultResponseHeaders();
2305         defaultRequestQueryData = builder.defaultRequestQueryData();
2306         defaultRequestFormData = builder.defaultRequestFormData();
2307         defaultRequestAttributes = builder.defaultRequestAttributes();
2308
2309         int _hierarchyDepth = 0;
2310         Class<?> sc = method.getDeclaringClass().getSuperclass();
2311         while (sc != null) {
2312            _hierarchyDepth++;
2313            sc = sc.getSuperclass();
2314         }
2315         hierarchyDepth = _hierarchyDepth;
2316
2317         String _httpMethod = builder.httpMethod;
2318         if (_httpMethod == null)
2319            _httpMethod = HttpUtils.detectHttpMethod(method, true, "GET");
2320         if ("METHOD".equals(_httpMethod))
2321            _httpMethod = "*";
2322         httpMethod = _httpMethod.toUpperCase(Locale.ENGLISH);
2323
2324         defaultCharset = builder.defaultCharset != null ? builder.defaultCharset : context.defaultCharset;
2325         maxInput = builder.maxInput != null ? builder.maxInput : context.maxInput;
2326
2327         responseMeta = ResponseBeanMeta.create(mi, builder.getApplied());
2328
2329         preCallMethods = context.getPreCallMethods().stream().map(x -> new RestOpInvoker(x, context.findRestOperationArgs(x, bs), context.getMethodExecStats(x))).toArray(RestOpInvoker[]::new);
2330         postCallMethods = context.getPostCallMethods().stream().map(x -> new RestOpInvoker(x, context.findRestOperationArgs(x, bs), context.getMethodExecStats(x))).toArray(RestOpInvoker[]::new);
2331         methodInvoker = new RestOpInvoker(method, context.findRestOperationArgs(method, bs), context.getMethodExecStats(method));
2332
2333         this.callLogger = context.getCallLogger();
2334      } catch (Exception e) {
2335         throw new ServletException(e);
2336      }
2337   }
2338
2339   /**
2340    * Creates a new REST operation session.
2341    *
2342    * @param session The REST session.
2343    * @return A new REST operation session.
2344    * @throws Exception If op session could not be created.
2345    */
2346   public RestOpSession.Builder createSession(RestSession session) throws Exception {
2347      return RestOpSession.create(this, session).logger(callLogger).debug(debug.isDebug(this, session.getRequest()));
2348   }
2349
2350   /**
2351    * Creates a {@link RestRequest} object based on the specified incoming {@link HttpServletRequest} object.
2352    *
2353    * @param session The current REST call.
2354    * @return The wrapped request object.
2355    * @throws Exception If any errors occur trying to interpret the request.
2356    */
2357   public RestRequest createRequest(RestSession session) throws Exception {
2358      return new RestRequest(this, session);
2359   }
2360
2361   /**
2362    * Creates a {@link RestResponse} object based on the specified incoming {@link HttpServletResponse} object
2363    * and the request returned by {@link #createRequest(RestSession)}.
2364    *
2365    * @param session The current REST call.
2366    * @param req The REST request.
2367    * @return The wrapped response object.
2368    * @throws Exception If any errors occur trying to interpret the request or response.
2369    */
2370   public RestResponse createResponse(RestSession session, RestRequest req) throws Exception {
2371      return new RestResponse(this, session, req);
2372   }
2373
2374   /**
2375    * Returns the bean context associated with this context.
2376    *
2377    * @return The bean context associated with this context.
2378    */
2379   public BeanContext getBeanContext() {
2380      return beanContext;
2381   }
2382
2383   /**
2384    * Returns metadata about the specified response object if it's annotated with {@link Response @Response}.
2385    *
2386    * @param o The response POJO.
2387    * @return Metadata about the specified response object, or <jk>null</jk> if it's not annotated with {@link Response @Response}.
2388    */
2389   public ResponseBeanMeta getResponseBeanMeta(Object o) {
2390      if (o == null)
2391         return null;
2392      Class<?> c = o.getClass();
2393      ResponseBeanMeta rbm = responseBeanMetas.get(c);
2394      if (rbm == null) {
2395         rbm = ResponseBeanMeta.create(c, AnnotationWorkList.create());
2396         if (rbm == null)
2397            rbm = ResponseBeanMeta.NULL;
2398         responseBeanMetas.put(c, rbm);
2399      }
2400      if (rbm == ResponseBeanMeta.NULL)
2401         return null;
2402      return rbm;
2403   }
2404
2405   /**
2406    * Returns metadata about the specified response object if it's annotated with {@link Header @Header}.
2407    *
2408    * @param o The response POJO.
2409    * @return Metadata about the specified response object, or <jk>null</jk> if it's not annotated with {@link Header @Header}.
2410    */
2411   public ResponsePartMeta getResponseHeaderMeta(Object o) {
2412      if (o == null)
2413         return null;
2414      Class<?> c = o.getClass();
2415      ResponsePartMeta pm = headerPartMetas.get(c);
2416      if (pm == null) {
2417         Header a = c.getAnnotation(Header.class);
2418         if (a != null) {
2419            HttpPartSchema schema = HttpPartSchema.create(a);
2420            HttpPartSerializer serializer = createPartSerializer(schema.getSerializer(), partSerializer);
2421            pm = new ResponsePartMeta(HEADER, schema, serializer);
2422         }
2423         if (pm == null)
2424            pm = ResponsePartMeta.NULL;
2425         headerPartMetas.put(c, pm);
2426      }
2427      if (pm == ResponsePartMeta.NULL)
2428         return null;
2429      return pm;
2430   }
2431
2432   /**
2433    * Returns the HTTP method name (e.g. <js>"GET"</js>).
2434    *
2435    * @return The HTTP method name.
2436    */
2437   public String getHttpMethod() {
2438      return httpMethod;
2439   }
2440
2441   /**
2442    * Returns the path pattern for this method.
2443    *
2444    * @return The path pattern.
2445    */
2446   public String getPathPattern() {
2447      return pathMatchers[0].toString();
2448   }
2449
2450   /**
2451    * Returns the serializers to use for this method.
2452    *
2453    * @return The serializers to use for this method.
2454    */
2455   public SerializerSet getSerializers() {
2456      return serializers;
2457   }
2458
2459   /**
2460    * Returns the parsers to use for this method.
2461    *
2462    * @return The parsers to use for this method.
2463    */
2464   public ParserSet getParsers() {
2465      return parsers;
2466   }
2467
2468   /**
2469    * Returns the compression encoders to use for this method.
2470    *
2471    * @return The compression encoders to use for this method.
2472    */
2473   public EncoderSet getEncoders() {
2474      return encoders;
2475   }
2476
2477   /**
2478    * Bean property getter:  <property>partSerializer</property>.
2479    *
2480    * @return The value of the <property>partSerializer</property> property on this bean, or <jk>null</jk> if it is not set.
2481    */
2482   public HttpPartSerializer getPartSerializer() {
2483      return partSerializer;
2484   }
2485
2486   /**
2487    * Bean property getter:  <property>partParser</property>.
2488    *
2489    * @return The value of the <property>partParser</property> property on this bean, or <jk>null</jk> if it is not set.
2490    */
2491   public HttpPartParser getPartParser() {
2492      return partParser;
2493   }
2494
2495   /**
2496    * Returns the JSON-Schema generator applicable to this Java method.
2497    *
2498    * @return The JSON-Schema generator applicable to this Java method.
2499    */
2500   public JsonSchemaGenerator getJsonSchemaGenerator() {
2501      return jsonSchemaGenerator;
2502   }
2503
2504   /**
2505    * Returns the underlying Java method that this context belongs to.
2506    *
2507    * @return The underlying Java method that this context belongs to.
2508    */
2509   public Method getJavaMethod() {
2510      return method;
2511   }
2512
2513   /**
2514    * Returns the default request headers.
2515    *
2516    * @return The default request headers.  Never <jk>null</jk>.
2517    */
2518   public HeaderList getDefaultRequestHeaders() {
2519      return defaultRequestHeaders;
2520   }
2521
2522   /**
2523    * Returns the default response headers.
2524    *
2525    * @return The default response headers.  Never <jk>null</jk>.
2526    */
2527   public HeaderList getDefaultResponseHeaders() {
2528      return defaultResponseHeaders;
2529   }
2530
2531   /**
2532    * Returns the default request query parameters.
2533    *
2534    * @return The default request query parameters.  Never <jk>null</jk>.
2535    */
2536   public PartList getDefaultRequestQueryData() {
2537      return defaultRequestQueryData;
2538   }
2539
2540   /**
2541    * Returns the default form data parameters.
2542    *
2543    * @return The default form data parameters.  Never <jk>null</jk>.
2544    */
2545   public PartList getDefaultRequestFormData() {
2546      return defaultRequestFormData;
2547   }
2548
2549   /**
2550    * Returns the default request attributes.
2551    *
2552    * @return The default request attributes.  Never <jk>null</jk>.
2553    */
2554   public NamedAttributeMap getDefaultRequestAttributes() {
2555      return defaultRequestAttributes;
2556   }
2557
2558   /**
2559    * Returns the default charset.
2560    *
2561    * @return The default charset.  Never <jk>null</jk>.
2562    */
2563   public Charset getDefaultCharset() {
2564      return defaultCharset;
2565   }
2566
2567   /**
2568    * Returns the max number of bytes to process in the input content.
2569    *
2570    * @return The max number of bytes to process in the input content.
2571    */
2572   public long getMaxInput() {
2573      return maxInput;
2574   }
2575
2576   /**
2577    * Returns the list of supported content types.
2578    *
2579    * @return An unmodifiable list.
2580    */
2581   public List<MediaType> getSupportedContentTypes() {
2582      return supportedContentTypes;
2583   }
2584
2585   /**
2586    * Returns a list of supported accept types.
2587    *
2588    * @return An unmodifiable list.
2589    */
2590   public List<MediaType> getSupportedAcceptTypes() {
2591      return supportedAcceptTypes;
2592   }
2593
2594   /**
2595    * Returns the response bean meta if this method returns a {@link Response}-annotated bean.
2596    *
2597    * @return The response bean meta or <jk>null</jk> if it's not a {@link Response}-annotated bean.
2598    */
2599   public ResponseBeanMeta getResponseMeta() {
2600      return responseMeta;
2601   }
2602
2603   /**
2604    * Identifies if this method can process the specified call.
2605    *
2606    * <p>
2607    * To process the call, the following must be true:
2608    * <ul>
2609    *    <li>Path pattern must match.
2610    *    <li>Matchers (if any) must match.
2611    * </ul>
2612    *
2613    * @param session The call to check.
2614    * @return
2615    *    One of the following values:
2616    *    <ul>
2617    *       <li><c>0</c> - Path doesn't match.
2618    *       <li><c>1</c> - Path matched but matchers did not.
2619    *       <li><c>2</c> - Matches.
2620    *    </ul>
2621    */
2622   protected int match(RestSession session) {
2623
2624      UrlPathMatch pm = matchPattern(session);
2625
2626      if (pm == null)
2627         return 0;
2628
2629      if (requiredMatchers.length == 0 && optionalMatchers.length == 0) {
2630         session.urlPathMatch(pm);  // Cache so we don't have to recalculate.
2631         return 2;
2632      }
2633
2634      try {
2635         HttpServletRequest req = session.getRequest();
2636
2637         // If the method implements matchers, test them.
2638         for (RestMatcher m :  requiredMatchers)
2639            if (! m.matches(req))
2640               return 1;
2641         if (optionalMatchers.length > 0) {
2642            boolean matches = false;
2643            for (RestMatcher m : optionalMatchers)
2644               matches |= m.matches(req);
2645            if (! matches)
2646               return 1;
2647         }
2648
2649         session.urlPathMatch(pm);  // Cache so we don't have to recalculate.
2650         return 2;
2651      } catch (Exception e) {
2652         throw new InternalServerError(e);
2653      }
2654   }
2655
2656   RestOpInvoker getMethodInvoker() {
2657      return methodInvoker;
2658   }
2659
2660   RestGuard[] getGuards() {
2661      return guards;
2662   }
2663
2664   RestConverter[] getConverters() {
2665      return converters;
2666   }
2667
2668   RestOpInvoker[] getPreCallMethods() {
2669      return preCallMethods;
2670   }
2671
2672   RestOpInvoker[] getPostCallMethods() {
2673      return postCallMethods;
2674   }
2675
2676   //-----------------------------------------------------------------------------------------------------------------
2677   // Other methods
2678   //-----------------------------------------------------------------------------------------------------------------
2679
2680   @Override /* Context */
2681   public Context.Builder copy() {
2682      throw new UnsupportedOperationException("Method not implemented.");
2683   }
2684
2685   /*
2686    * compareTo() method is used to keep SimpleMethods ordered in the RestCallRouter list.
2687    * It maintains the order in which matches are made during requests.
2688    */
2689   @Override /* Comparable */
2690   public int compareTo(RestOpContext o) {
2691      int c;
2692
2693      for (int i = 0; i < Math.min(pathMatchers.length, o.pathMatchers.length); i++) {
2694         c = pathMatchers[i].compareTo(o.pathMatchers[i]);
2695         if (c != 0)
2696            return c;
2697      }
2698
2699      c = compare(o.hierarchyDepth, hierarchyDepth);
2700      if (c != 0)
2701         return c;
2702
2703      c = compare(o.requiredMatchers.length, requiredMatchers.length);
2704      if (c != 0)
2705         return c;
2706
2707      c = compare(o.optionalMatchers.length, optionalMatchers.length);
2708      if (c != 0)
2709         return c;
2710
2711      c = compare(o.guards.length, guards.length);
2712
2713      if (c != 0)
2714         return c;
2715
2716      c = compare(method.getName(), o.method.getName());
2717      if (c != 0)
2718         return c;
2719
2720      c = compare(method.getParameterCount(), o.method.getParameterCount());
2721      if (c != 0)
2722         return c;
2723
2724      for (int i = 0; i < method.getParameterCount(); i++) {
2725         c = compare(method.getParameterTypes()[i].getName(), o.method.getParameterTypes()[i].getName());
2726         if (c != 0)
2727            return c;
2728      }
2729
2730      c = compare(method.getReturnType().getName(), o.method.getReturnType().getName());
2731      if (c != 0)
2732         return c;
2733
2734      return 0;
2735   }
2736
2737   @Override /* Object */
2738   public boolean equals(Object o) {
2739      return (o instanceof RestOpContext) && eq(this, (RestOpContext)o, (x,y)->x.method.equals(y.method));
2740   }
2741
2742   @Override /* Object */
2743   public int hashCode() {
2744      return method.hashCode();
2745   }
2746
2747   @Override /* Context */
2748   protected JsonMap properties() {
2749      return filteredMap()
2750         .append("defaultRequestFormData", defaultRequestFormData)
2751         .append("defaultRequestHeaders", defaultRequestHeaders)
2752         .append("defaultRequestQueryData", defaultRequestQueryData)
2753         .append("httpMethod", httpMethod);
2754   }
2755
2756   //-----------------------------------------------------------------------------------------------------------------
2757   // Helper methods.
2758   //-----------------------------------------------------------------------------------------------------------------
2759
2760   private static HttpPartSerializer createPartSerializer(Class<? extends HttpPartSerializer> c, HttpPartSerializer _default) {
2761      return BeanCreator.of(HttpPartSerializer.class).type(c).orElse(_default);
2762   }
2763
2764   private UrlPathMatch matchPattern(RestSession call) {
2765      UrlPathMatch pm = null;
2766      for (UrlPathMatcher pp : pathMatchers)
2767         if (pm == null)
2768            pm = pp.match(call.getUrlPath());
2769      return pm;
2770   }
2771}