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.HttpPartSerializer.Creator;
048import org.apache.juneau.httppart.bean.*;
049import org.apache.juneau.internal.*;
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(this::matches)
334            .run(x -> v.get().impl(x));
335
336         return v.get();
337      }
338
339      Optional<BeanContext> getBeanContext() {
340         return optional(beanContext).map(BeanContext.Builder::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(this::matches)
417            .run(x -> v.get().impl(x));
418
419         return v.get();
420      }
421
422      Optional<EncoderSet> getEncoders() {
423         return optional(encoders).map(EncoderSet.Builder::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(this::matches)
500            .run(x -> v.get().impl(x));
501
502         return v.get();
503      }
504
505      Optional<SerializerSet> getSerializers() {
506         return optional(serializers).map(SerializerSet.Builder::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(this::matches)
583            .run(x -> v.get().impl(x));
584
585         return v.get();
586      }
587
588      Optional<ParserSet> getParsers() {
589         return optional(parsers).map(ParserSet.Builder::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(this::matches)
665            .run(x -> v.get().impl(x));
666
667         return v.get();
668      }
669
670      Optional<HttpPartSerializer> getPartSerializer() {
671         return optional(partSerializer).map(Creator::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(this::matches)
747            .run(x -> v.get().impl(x));
748
749         return v.get();
750      }
751
752      Optional<HttpPartParser> getPartParser() {
753         return optional(partParser).map(org.apache.juneau.httppart.HttpPartParser.Creator::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(this::matches)
829            .run(x -> v.get().impl(x));
830
831         return v.get();
832      }
833
834      Optional<JsonSchemaGenerator> getJsonSchemaGenerator() {
835         return optional(jsonSchemaGenerator).map(JsonSchemaGenerator.Builder::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(this::matches)
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(this::matches)
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(CollectionUtils::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(this::matches)
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(this::matches)
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) || restMethod.getName().equals(n))
2185                  return true;
2186            }
2187         }
2188         return false;
2189      }
2190
2191      private boolean matches(MethodInfo annotated, String beanName) {
2192         RestInject a = annotated.getAnnotation(RestInject.class);
2193         if (a != null) {
2194            if (! a.name().equals(beanName))
2195               return false;
2196            for (String n : a.methodScope()) {
2197               if ("*".equals(n) || restMethod.getName().equals(n))
2198                  return true;
2199            }
2200         }
2201         return false;
2202      }
2203
2204      private String joinnlFirstNonEmptyArray(String[]...s) {
2205         for (String[] ss : s)
2206            if (ss.length > 0)
2207               return joinnl(ss);
2208         return null;
2209      }
2210
2211   }
2212
2213   //-------------------------------------------------------------------------------------------------------------------
2214   // Instance
2215   //-------------------------------------------------------------------------------------------------------------------
2216
2217   private final String httpMethod;
2218   private final UrlPathMatcher[] pathMatchers;
2219   private final RestGuard[] guards;
2220   private final RestMatcher[] requiredMatchers, optionalMatchers;
2221   private final RestConverter[] converters;
2222   private final RestContext context;
2223   private final Method method;
2224   private final RestOpInvoker methodInvoker;
2225   private final RestOpInvoker[]
2226      preCallMethods,
2227      postCallMethods;
2228   private final MethodInfo mi;
2229   private final BeanContext beanContext;
2230   private final SerializerSet serializers;
2231   private final ParserSet parsers;
2232   private final EncoderSet encoders;
2233   private final HttpPartSerializer partSerializer;
2234   private final HttpPartParser partParser;
2235   private final JsonSchemaGenerator jsonSchemaGenerator;
2236   private final HeaderList defaultRequestHeaders, defaultResponseHeaders;
2237   private final PartList defaultRequestQueryData, defaultRequestFormData;
2238   private final NamedAttributeMap defaultRequestAttributes;
2239   private final Charset defaultCharset;
2240   private final long maxInput;
2241   private final List<MediaType>
2242      supportedAcceptTypes,
2243      supportedContentTypes;
2244   private final CallLogger callLogger;
2245
2246   private final Map<Class<?>,ResponseBeanMeta> responseBeanMetas = new ConcurrentHashMap<>();
2247   private final Map<Class<?>,ResponsePartMeta> headerPartMetas = new ConcurrentHashMap<>();
2248   private final ResponseBeanMeta responseMeta;
2249   private final int hierarchyDepth;
2250   private final DebugEnablement debug;
2251
2252   /**
2253    * Context constructor.
2254    *
2255    * @param builder The builder for this object.
2256    * @throws ServletException If context could not be created.
2257    */
2258   protected RestOpContext(Builder builder) throws ServletException {
2259      super(builder);
2260
2261      try {
2262         context = builder.restContext;
2263         method = builder.restMethod;
2264
2265         if (builder.debug == null)
2266            debug = context.getDebugEnablement();
2267         else
2268            debug = DebugEnablement.create(context.getBeanStore()).enable(builder.debug, "*").build();
2269
2270         mi = MethodInfo.of(method).accessible();
2271         Object r = context.getResource();
2272
2273         BeanStore bs = BeanStore.of(context.getRootBeanStore(), r)
2274            .addBean(RestOpContext.class, this)
2275            .addBean(Method.class, method)
2276            .addBean(AnnotationWorkList.class, builder.getApplied());
2277         bs.addBean(BeanStore.class, bs);
2278
2279         beanContext = bs.add(BeanContext.class, builder.getBeanContext().orElse(context.getBeanContext()));
2280         encoders = bs.add(EncoderSet.class, builder.getEncoders().orElse(context.getEncoders()));
2281         serializers = bs.add(SerializerSet.class, builder.getSerializers().orElse(context.getSerializers()));
2282         parsers = bs.add(ParserSet.class, builder.getParsers().orElse(context.getParsers()));
2283         partSerializer = bs.add(HttpPartSerializer.class, builder.getPartSerializer().orElse(context.getPartSerializer()));
2284         partParser = bs.add(HttpPartParser.class, builder.getPartParser().orElse(context.getPartParser()));
2285         jsonSchemaGenerator = bs.add(JsonSchemaGenerator.class, builder.getJsonSchemaGenerator().orElse(context.getJsonSchemaGenerator()));
2286         converters = bs.add(RestConverter[].class, builder.converters().build().asArray());
2287         guards = bs.add(RestGuard[].class, builder.getGuards().asArray());
2288
2289         RestMatcherList matchers = builder.getMatchers(context);
2290         optionalMatchers = matchers.getOptionalEntries();
2291         requiredMatchers = matchers.getRequiredEntries();
2292
2293         pathMatchers = bs.add(UrlPathMatcher[].class, builder.getPathMatchers().asArray());
2294         bs.addBean(UrlPathMatcher.class, pathMatchers.length > 0 ? pathMatchers[0] : null);
2295
2296         supportedAcceptTypes = unmodifiable(builder.produces != null ? builder.produces : serializers.getSupportedMediaTypes());
2297         supportedContentTypes = unmodifiable(builder.consumes != null ? builder.consumes : parsers.getSupportedMediaTypes());
2298
2299         defaultRequestHeaders = builder.defaultRequestHeaders();
2300         defaultResponseHeaders = builder.defaultResponseHeaders();
2301         defaultRequestQueryData = builder.defaultRequestQueryData();
2302         defaultRequestFormData = builder.defaultRequestFormData();
2303         defaultRequestAttributes = builder.defaultRequestAttributes();
2304
2305         int _hierarchyDepth = 0;
2306         Class<?> sc = method.getDeclaringClass().getSuperclass();
2307         while (sc != null) {
2308            _hierarchyDepth++;
2309            sc = sc.getSuperclass();
2310         }
2311         hierarchyDepth = _hierarchyDepth;
2312
2313         String _httpMethod = builder.httpMethod;
2314         if (_httpMethod == null)
2315            _httpMethod = HttpUtils.detectHttpMethod(method, true, "GET");
2316         if ("METHOD".equals(_httpMethod))
2317            _httpMethod = "*";
2318         httpMethod = _httpMethod.toUpperCase(Locale.ENGLISH);
2319
2320         defaultCharset = builder.defaultCharset != null ? builder.defaultCharset : context.defaultCharset;
2321         maxInput = builder.maxInput != null ? builder.maxInput : context.maxInput;
2322
2323         responseMeta = ResponseBeanMeta.create(mi, builder.getApplied());
2324
2325         preCallMethods = context.getPreCallMethods().stream().map(x -> new RestOpInvoker(x, context.findRestOperationArgs(x, bs), context.getMethodExecStats(x))).toArray(RestOpInvoker[]::new);
2326         postCallMethods = context.getPostCallMethods().stream().map(x -> new RestOpInvoker(x, context.findRestOperationArgs(x, bs), context.getMethodExecStats(x))).toArray(RestOpInvoker[]::new);
2327         methodInvoker = new RestOpInvoker(method, context.findRestOperationArgs(method, bs), context.getMethodExecStats(method));
2328
2329         this.callLogger = context.getCallLogger();
2330      } catch (Exception e) {
2331         throw new ServletException(e);
2332      }
2333   }
2334
2335   /**
2336    * Creates a new REST operation session.
2337    *
2338    * @param session The REST session.
2339    * @return A new REST operation session.
2340    * @throws Exception If op session could not be created.
2341    */
2342   public RestOpSession.Builder createSession(RestSession session) throws Exception {
2343      return RestOpSession.create(this, session).logger(callLogger).debug(debug.isDebug(this, session.getRequest()));
2344   }
2345
2346   /**
2347    * Creates a {@link RestRequest} object based on the specified incoming {@link HttpServletRequest} object.
2348    *
2349    * @param session The current REST call.
2350    * @return The wrapped request object.
2351    * @throws Exception If any errors occur trying to interpret the request.
2352    */
2353   public RestRequest createRequest(RestSession session) throws Exception {
2354      return new RestRequest(this, session);
2355   }
2356
2357   /**
2358    * Creates a {@link RestResponse} object based on the specified incoming {@link HttpServletResponse} object
2359    * and the request returned by {@link #createRequest(RestSession)}.
2360    *
2361    * @param session The current REST call.
2362    * @param req The REST request.
2363    * @return The wrapped response object.
2364    * @throws Exception If any errors occur trying to interpret the request or response.
2365    */
2366   public RestResponse createResponse(RestSession session, RestRequest req) throws Exception {
2367      return new RestResponse(this, session, req);
2368   }
2369
2370   /**
2371    * Returns the bean context associated with this context.
2372    *
2373    * @return The bean context associated with this context.
2374    */
2375   public BeanContext getBeanContext() {
2376      return beanContext;
2377   }
2378
2379   /**
2380    * Returns metadata about the specified response object if it's annotated with {@link Response @Response}.
2381    *
2382    * @param o The response POJO.
2383    * @return Metadata about the specified response object, or <jk>null</jk> if it's not annotated with {@link Response @Response}.
2384    */
2385   public ResponseBeanMeta getResponseBeanMeta(Object o) {
2386      if (o == null)
2387         return null;
2388      Class<?> c = o.getClass();
2389      ResponseBeanMeta rbm = responseBeanMetas.get(c);
2390      if (rbm == null) {
2391         rbm = ResponseBeanMeta.create(c, AnnotationWorkList.create());
2392         if (rbm == null)
2393            rbm = ResponseBeanMeta.NULL;
2394         responseBeanMetas.put(c, rbm);
2395      }
2396      if (rbm == ResponseBeanMeta.NULL)
2397         return null;
2398      return rbm;
2399   }
2400
2401   /**
2402    * Returns metadata about the specified response object if it's annotated with {@link Header @Header}.
2403    *
2404    * @param o The response POJO.
2405    * @return Metadata about the specified response object, or <jk>null</jk> if it's not annotated with {@link Header @Header}.
2406    */
2407   public ResponsePartMeta getResponseHeaderMeta(Object o) {
2408      if (o == null)
2409         return null;
2410      Class<?> c = o.getClass();
2411      ResponsePartMeta pm = headerPartMetas.get(c);
2412      if (pm == null) {
2413         Header a = c.getAnnotation(Header.class);
2414         if (a != null) {
2415            HttpPartSchema schema = HttpPartSchema.create(a);
2416            HttpPartSerializer serializer = createPartSerializer(schema.getSerializer(), partSerializer);
2417            pm = new ResponsePartMeta(HEADER, schema, serializer);
2418         }
2419         if (pm == null)
2420            pm = ResponsePartMeta.NULL;
2421         headerPartMetas.put(c, pm);
2422      }
2423      if (pm == ResponsePartMeta.NULL)
2424         return null;
2425      return pm;
2426   }
2427
2428   /**
2429    * Returns the HTTP method name (e.g. <js>"GET"</js>).
2430    *
2431    * @return The HTTP method name.
2432    */
2433   public String getHttpMethod() {
2434      return httpMethod;
2435   }
2436
2437   /**
2438    * Returns the path pattern for this method.
2439    *
2440    * @return The path pattern.
2441    */
2442   public String getPathPattern() {
2443      return pathMatchers[0].toString();
2444   }
2445
2446   /**
2447    * Returns the serializers to use for this method.
2448    *
2449    * @return The serializers to use for this method.
2450    */
2451   public SerializerSet getSerializers() {
2452      return serializers;
2453   }
2454
2455   /**
2456    * Returns the parsers to use for this method.
2457    *
2458    * @return The parsers to use for this method.
2459    */
2460   public ParserSet getParsers() {
2461      return parsers;
2462   }
2463
2464   /**
2465    * Returns the compression encoders to use for this method.
2466    *
2467    * @return The compression encoders to use for this method.
2468    */
2469   public EncoderSet getEncoders() {
2470      return encoders;
2471   }
2472
2473   /**
2474    * Bean property getter:  <property>partSerializer</property>.
2475    *
2476    * @return The value of the <property>partSerializer</property> property on this bean, or <jk>null</jk> if it is not set.
2477    */
2478   public HttpPartSerializer getPartSerializer() {
2479      return partSerializer;
2480   }
2481
2482   /**
2483    * Bean property getter:  <property>partParser</property>.
2484    *
2485    * @return The value of the <property>partParser</property> property on this bean, or <jk>null</jk> if it is not set.
2486    */
2487   public HttpPartParser getPartParser() {
2488      return partParser;
2489   }
2490
2491   /**
2492    * Returns the JSON-Schema generator applicable to this Java method.
2493    *
2494    * @return The JSON-Schema generator applicable to this Java method.
2495    */
2496   public JsonSchemaGenerator getJsonSchemaGenerator() {
2497      return jsonSchemaGenerator;
2498   }
2499
2500   /**
2501    * Returns the underlying Java method that this context belongs to.
2502    *
2503    * @return The underlying Java method that this context belongs to.
2504    */
2505   public Method getJavaMethod() {
2506      return method;
2507   }
2508
2509   /**
2510    * Returns the default request headers.
2511    *
2512    * @return The default request headers.  Never <jk>null</jk>.
2513    */
2514   public HeaderList getDefaultRequestHeaders() {
2515      return defaultRequestHeaders;
2516   }
2517
2518   /**
2519    * Returns the default response headers.
2520    *
2521    * @return The default response headers.  Never <jk>null</jk>.
2522    */
2523   public HeaderList getDefaultResponseHeaders() {
2524      return defaultResponseHeaders;
2525   }
2526
2527   /**
2528    * Returns the default request query parameters.
2529    *
2530    * @return The default request query parameters.  Never <jk>null</jk>.
2531    */
2532   public PartList getDefaultRequestQueryData() {
2533      return defaultRequestQueryData;
2534   }
2535
2536   /**
2537    * Returns the default form data parameters.
2538    *
2539    * @return The default form data parameters.  Never <jk>null</jk>.
2540    */
2541   public PartList getDefaultRequestFormData() {
2542      return defaultRequestFormData;
2543   }
2544
2545   /**
2546    * Returns the default request attributes.
2547    *
2548    * @return The default request attributes.  Never <jk>null</jk>.
2549    */
2550   public NamedAttributeMap getDefaultRequestAttributes() {
2551      return defaultRequestAttributes;
2552   }
2553
2554   /**
2555    * Returns the default charset.
2556    *
2557    * @return The default charset.  Never <jk>null</jk>.
2558    */
2559   public Charset getDefaultCharset() {
2560      return defaultCharset;
2561   }
2562
2563   /**
2564    * Returns the max number of bytes to process in the input content.
2565    *
2566    * @return The max number of bytes to process in the input content.
2567    */
2568   public long getMaxInput() {
2569      return maxInput;
2570   }
2571
2572   /**
2573    * Returns the list of supported content types.
2574    *
2575    * @return An unmodifiable list.
2576    */
2577   public List<MediaType> getSupportedContentTypes() {
2578      return supportedContentTypes;
2579   }
2580
2581   /**
2582    * Returns a list of supported accept types.
2583    *
2584    * @return An unmodifiable list.
2585    */
2586   public List<MediaType> getSupportedAcceptTypes() {
2587      return supportedAcceptTypes;
2588   }
2589
2590   /**
2591    * Returns the response bean meta if this method returns a {@link Response}-annotated bean.
2592    *
2593    * @return The response bean meta or <jk>null</jk> if it's not a {@link Response}-annotated bean.
2594    */
2595   public ResponseBeanMeta getResponseMeta() {
2596      return responseMeta;
2597   }
2598
2599   /**
2600    * Identifies if this method can process the specified call.
2601    *
2602    * <p>
2603    * To process the call, the following must be true:
2604    * <ul>
2605    *    <li>Path pattern must match.
2606    *    <li>Matchers (if any) must match.
2607    * </ul>
2608    *
2609    * @param session The call to check.
2610    * @return
2611    *    One of the following values:
2612    *    <ul>
2613    *       <li><c>0</c> - Path doesn't match.
2614    *       <li><c>1</c> - Path matched but matchers did not.
2615    *       <li><c>2</c> - Matches.
2616    *    </ul>
2617    */
2618   protected int match(RestSession session) {
2619
2620      UrlPathMatch pm = matchPattern(session);
2621
2622      if (pm == null)
2623         return 0;
2624
2625      if (requiredMatchers.length == 0 && optionalMatchers.length == 0) {
2626         session.urlPathMatch(pm);  // Cache so we don't have to recalculate.
2627         return 2;
2628      }
2629
2630      try {
2631         HttpServletRequest req = session.getRequest();
2632
2633         // If the method implements matchers, test them.
2634         for (RestMatcher m :  requiredMatchers)
2635            if (! m.matches(req))
2636               return 1;
2637         if (optionalMatchers.length > 0) {
2638            boolean matches = false;
2639            for (RestMatcher m : optionalMatchers)
2640               matches |= m.matches(req);
2641            if (! matches)
2642               return 1;
2643         }
2644
2645         session.urlPathMatch(pm);  // Cache so we don't have to recalculate.
2646         return 2;
2647      } catch (Exception e) {
2648         throw new InternalServerError(e);
2649      }
2650   }
2651
2652   RestOpInvoker getMethodInvoker() {
2653      return methodInvoker;
2654   }
2655
2656   RestGuard[] getGuards() {
2657      return guards;
2658   }
2659
2660   RestConverter[] getConverters() {
2661      return converters;
2662   }
2663
2664   RestOpInvoker[] getPreCallMethods() {
2665      return preCallMethods;
2666   }
2667
2668   RestOpInvoker[] getPostCallMethods() {
2669      return postCallMethods;
2670   }
2671
2672   //-----------------------------------------------------------------------------------------------------------------
2673   // Other methods
2674   //-----------------------------------------------------------------------------------------------------------------
2675
2676   @Override /* Context */
2677   public Context.Builder copy() {
2678      throw new UnsupportedOperationException("Method not implemented.");
2679   }
2680
2681   /*
2682    * compareTo() method is used to keep SimpleMethods ordered in the RestCallRouter list.
2683    * It maintains the order in which matches are made during requests.
2684    */
2685   @Override /* Comparable */
2686   public int compareTo(RestOpContext o) {
2687      int c;
2688
2689      for (int i = 0; i < Math.min(pathMatchers.length, o.pathMatchers.length); i++) {
2690         c = pathMatchers[i].compareTo(o.pathMatchers[i]);
2691         if (c != 0)
2692            return c;
2693      }
2694
2695      c = compare(o.hierarchyDepth, hierarchyDepth);
2696      if (c != 0)
2697         return c;
2698
2699      c = compare(o.requiredMatchers.length, requiredMatchers.length);
2700      if (c != 0)
2701         return c;
2702
2703      c = compare(o.optionalMatchers.length, optionalMatchers.length);
2704      if (c != 0)
2705         return c;
2706
2707      c = compare(o.guards.length, guards.length);
2708
2709      if (c != 0)
2710         return c;
2711
2712      c = compare(method.getName(), o.method.getName());
2713      if (c != 0)
2714         return c;
2715
2716      c = compare(method.getParameterCount(), o.method.getParameterCount());
2717      if (c != 0)
2718         return c;
2719
2720      for (int i = 0; i < method.getParameterCount(); i++) {
2721         c = compare(method.getParameterTypes()[i].getName(), o.method.getParameterTypes()[i].getName());
2722         if (c != 0)
2723            return c;
2724      }
2725
2726      c = compare(method.getReturnType().getName(), o.method.getReturnType().getName());
2727      if (c != 0)
2728         return c;
2729
2730      return 0;
2731   }
2732
2733   @Override /* Object */
2734   public boolean equals(Object o) {
2735      return (o instanceof RestOpContext) && eq(this, (RestOpContext)o, (x,y)->x.method.equals(y.method));
2736   }
2737
2738   @Override /* Object */
2739   public int hashCode() {
2740      return method.hashCode();
2741   }
2742
2743   @Override /* Context */
2744   protected JsonMap properties() {
2745      return filteredMap()
2746         .append("defaultRequestFormData", defaultRequestFormData)
2747         .append("defaultRequestHeaders", defaultRequestHeaders)
2748         .append("defaultRequestQueryData", defaultRequestQueryData)
2749         .append("httpMethod", httpMethod);
2750   }
2751
2752   //-----------------------------------------------------------------------------------------------------------------
2753   // Helper methods.
2754   //-----------------------------------------------------------------------------------------------------------------
2755
2756   private static HttpPartSerializer createPartSerializer(Class<? extends HttpPartSerializer> c, HttpPartSerializer _default) {
2757      return BeanCreator.of(HttpPartSerializer.class).type(c).orElse(_default);
2758   }
2759
2760   private UrlPathMatch matchPattern(RestSession call) {
2761      UrlPathMatch pm = null;
2762      for (UrlPathMatcher pp : pathMatchers)
2763         if (pm == null)
2764            pm = pp.match(call.getUrlPath());
2765      return pm;
2766   }
2767}