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