001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.annotation;
014
015import static org.apache.juneau.internal.ArrayUtils.*;
016import java.lang.annotation.*;
017import java.nio.charset.*;
018import java.util.function.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.annotation.*;
022import org.apache.juneau.common.internal.*;
023import org.apache.juneau.encoders.*;
024import org.apache.juneau.http.HttpHeaders;
025import org.apache.juneau.http.HttpParts;
026import org.apache.juneau.reflect.*;
027import org.apache.juneau.rest.*;
028import org.apache.juneau.rest.converter.*;
029import org.apache.juneau.rest.guard.*;
030import org.apache.juneau.rest.httppart.*;
031import org.apache.juneau.rest.matcher.*;
032import org.apache.juneau.serializer.*;
033import org.apache.juneau.svl.*;
034
035/**
036 * Utility classes and methods for the {@link RestOp @RestOp} annotation.
037 *
038 * <h5 class='section'>See Also:</h5><ul>
039 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.RestOpAnnotatedMethods">@RestOp-Annotated Methods</a>
040 * </ul>
041 */
042public class RestOpAnnotation {
043
044   //-----------------------------------------------------------------------------------------------------------------
045   // Static
046   //-----------------------------------------------------------------------------------------------------------------
047
048   /** Default value */
049   public static final RestOp DEFAULT = create().build();
050
051   /**
052    * Predicate that can be used with the {@link ClassInfo#getAnnotationList(Predicate)} and {@link MethodInfo#getAnnotationList(Predicate)}
053    */
054   public static final Predicate<AnnotationInfo<?>> REST_OP_GROUP = x -> x.isInGroup(RestOp.class);
055
056   /**
057    * Instantiates a new builder for this class.
058    *
059    * @return A new builder object.
060    */
061   public static Builder create() {
062      return new Builder();
063   }
064
065   //-----------------------------------------------------------------------------------------------------------------
066   // Builder
067   //-----------------------------------------------------------------------------------------------------------------
068
069   /**
070    * Builder class.
071    *
072    * <h5 class='section'>See Also:</h5><ul>
073    *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)}
074    * </ul>
075    */
076   @SuppressWarnings("unchecked")
077   public static class Builder extends TargetedAnnotationMBuilder {
078
079      Class<? extends RestConverter>[] converters = new Class[0];
080      Class<? extends RestGuard>[] guards = new Class[0];
081      Class<? extends RestMatcher>[] matchers = new Class[0];
082      Class<? extends Encoder>[] encoders = new Class[0];
083      Class<? extends Serializer>[] serializers = new Class[0];
084      Class<?>[] parsers={};
085      OpSwagger swagger = OpSwaggerAnnotation.DEFAULT;
086      String clientVersion="", debug="", defaultAccept="", defaultCharset="", defaultContentType="", maxInput="", method="", rolesDeclared="", roleGuard="", summary="", value="";
087      String[] consumes={}, defaultRequestFormData={}, defaultRequestQueryData={}, defaultRequestAttributes={}, defaultRequestHeaders={}, defaultResponseHeaders={}, description={}, path={}, produces={};
088
089      /**
090       * Constructor.
091       */
092      protected Builder() {
093         super(RestOp.class);
094      }
095
096      /**
097       * Instantiates a new {@link RestOp @RestOp} object initialized with this builder.
098       *
099       * @return A new {@link RestOp @RestOp} object.
100       */
101      public RestOp build() {
102         return new Impl(this);
103      }
104
105      /**
106       * Sets the {@link RestOp#clientVersion()} property on this annotation.
107       *
108       * @param value The new value for this property.
109       * @return This object.
110       */
111      public Builder clientVersion(String value) {
112         this.clientVersion = value;
113         return this;
114      }
115
116      /**
117       * Sets the {@link RestOp#consumes()} property on this annotation.
118       *
119       * @param value The new value for this property.
120       * @return This object.
121       */
122      public Builder consumes(String...value) {
123         this.consumes = value;
124         return this;
125      }
126
127      /**
128       * Sets the {@link RestOp#converters()} property on this annotation.
129       *
130       * @param value The new value for this property.
131       * @return This object.
132       */
133      public Builder converters(Class<? extends RestConverter>...value) {
134         this.converters = value;
135         return this;
136      }
137
138      /**
139       * Sets the {@link RestOp#debug()} property on this annotation.
140       *
141       * @param value The new value for this property.
142       * @return This object.
143       */
144      public Builder debug(String value) {
145         this.debug = value;
146         return this;
147      }
148
149      /**
150       * Sets the {@link RestOp#defaultAccept()} property on this annotation.
151       *
152       * @param value The new value for this property.
153       * @return This object.
154       */
155      public Builder defaultAccept(String value) {
156         this.defaultAccept = value;
157         return this;
158      }
159
160      /**
161       * Sets the {@link RestOp#defaultCharset()} property on this annotation.
162       *
163       * @param value The new value for this property.
164       * @return This object.
165       */
166      public Builder defaultCharset(String value) {
167         this.defaultCharset = value;
168         return this;
169      }
170
171      /**
172       * Sets the {@link RestOp#defaultContentType()} property on this annotation.
173       *
174       * @param value The new value for this property.
175       * @return This object.
176       */
177      public Builder defaultContentType(String value) {
178         this.defaultContentType = value;
179         return this;
180      }
181
182      /**
183       * Sets the {@link RestOp#defaultRequestFormData()} property on this annotation.
184       *
185       * @param value The new value for this property.
186       * @return This object.
187       */
188      public Builder defaultRequestFormData(String...value) {
189         this.defaultRequestFormData = value;
190         return this;
191      }
192
193      /**
194       * Sets the {@link RestOp#defaultRequestQueryData()} property on this annotation.
195       *
196       * @param value The new value for this property.
197       * @return This object.
198       */
199      public Builder defaultRequestQueryData(String...value) {
200         this.defaultRequestQueryData = value;
201         return this;
202      }
203
204      /**
205       * Sets the {@link RestOp#defaultRequestAttributes()} property on this annotation.
206       *
207       * @param value The new value for this property.
208       * @return This object.
209       */
210      public Builder defaultRequestAttributes(String...value) {
211         this.defaultRequestAttributes = value;
212         return this;
213      }
214
215      /**
216       * Sets the {@link RestOp#defaultRequestHeaders()} property on this annotation.
217       *
218       * @param value The new value for this property.
219       * @return This object.
220       */
221      public Builder defaultRequestHeaders(String...value) {
222         this.defaultRequestHeaders = value;
223         return this;
224      }
225
226      /**
227       * Sets the {@link RestOp#defaultResponseHeaders()} property on this annotation.
228       *
229       * @param value The new value for this property.
230       * @return This object.
231       */
232      public Builder defaultResponseHeaders(String...value) {
233         this.defaultResponseHeaders = value;
234         return this;
235      }
236
237      /**
238       * Sets the {@link RestOp#description()} property on this annotation.
239       *
240       * @param value The new value for this property.
241       * @return This object.
242       */
243      public Builder description(String...value) {
244         this.description = value;
245         return this;
246      }
247
248      /**
249       * Sets the {@link RestOp#encoders()} property on this annotation.
250       *
251       * @param value The new value for this property.
252       * @return This object.
253       */
254      public Builder encoders(Class<? extends Encoder>...value) {
255         this.encoders = value;
256         return this;
257      }
258
259      /**
260       * Sets the {@link RestOp#guards()} property on this annotation.
261       *
262       * @param value The new value for this property.
263       * @return This object.
264       */
265      public Builder guards(Class<? extends RestGuard>...value) {
266         this.guards = value;
267         return this;
268      }
269
270      /**
271       * Sets the {@link RestOp#matchers()} property on this annotation.
272       *
273       * @param value The new value for this property.
274       * @return This object.
275       */
276      public Builder matchers(Class<? extends RestMatcher>...value) {
277         this.matchers = value;
278         return this;
279      }
280
281      /**
282       * Sets the {@link RestOp#maxInput()} property on this annotation.
283       *
284       * @param value The new value for this property.
285       * @return This object.
286       */
287      public Builder maxInput(String value) {
288         this.maxInput = value;
289         return this;
290      }
291
292      /**
293       * Sets the {@link RestOp#method()} property on this annotation.
294       *
295       * @param value The new value for this property.
296       * @return This object.
297       */
298      public Builder method(String value) {
299         this.method = value;
300         return this;
301      }
302
303      /**
304       * Sets the {@link RestOp#parsers()} property on this annotation.
305       *
306       * @param value The new value for this property.
307       * @return This object.
308       */
309      public Builder parsers(Class<?>...value) {
310         this.parsers = value;
311         return this;
312      }
313
314      /**
315       * Sets the {@link RestOp#path()} property on this annotation.
316       *
317       * @param value The new value for this property.
318       * @return This object.
319       */
320      public Builder path(String...value) {
321         this.path = value;
322         return this;
323      }
324
325      /**
326       * Sets the {@link RestOp#produces()} property on this annotation.
327       *
328       * @param value The new value for this property.
329       * @return This object.
330       */
331      public Builder produces(String...value) {
332         this.produces = value;
333         return this;
334      }
335
336      /**
337       * Sets the {@link RestOp#roleGuard()} property on this annotation.
338       *
339       * @param value The new value for this property.
340       * @return This object.
341       */
342      public Builder roleGuard(String value) {
343         this.roleGuard = value;
344         return this;
345      }
346
347      /**
348       * Sets the {@link RestOp#rolesDeclared()} property on this annotation.
349       *
350       * @param value The new value for this property.
351       * @return This object.
352       */
353      public Builder rolesDeclared(String value) {
354         this.rolesDeclared = value;
355         return this;
356      }
357
358      /**
359       * Sets the {@link RestOp#serializers()} property on this annotation.
360       *
361       * @param value The new value for this property.
362       * @return This object.
363       */
364      public Builder serializers(Class<? extends Serializer>...value) {
365         this.serializers = value;
366         return this;
367      }
368
369      /**
370       * Sets the {@link RestOp#summary()} property on this annotation.
371       *
372       * @param value The new value for this property.
373       * @return This object.
374       */
375      public Builder summary(String value) {
376         this.summary = value;
377         return this;
378      }
379
380      /**
381       * Sets the {@link RestOp#swagger()} property on this annotation.
382       *
383       * @param value The new value for this property.
384       * @return This object.
385       */
386      public Builder swagger(OpSwagger value) {
387         this.swagger = value;
388         return this;
389      }
390
391      /**
392       * Sets the {@link RestOp#value()} property on this annotation.
393       *
394       * @param value The new value for this property.
395       * @return This object.
396       */
397      public Builder value(String value) {
398         this.value = value;
399         return this;
400      }
401
402      // <FluentSetters>
403
404      @Override /* GENERATED - TargetedAnnotationBuilder */
405      public Builder on(String...values) {
406         super.on(values);
407         return this;
408      }
409
410      @Override /* GENERATED - TargetedAnnotationTMBuilder */
411      public Builder on(java.lang.reflect.Method...value) {
412         super.on(value);
413         return this;
414      }
415
416      // </FluentSetters>
417   }
418
419   //-----------------------------------------------------------------------------------------------------------------
420   // Implementation
421   //-----------------------------------------------------------------------------------------------------------------
422
423   private static class Impl extends TargetedAnnotationImpl implements RestOp {
424
425      private final Class<? extends RestConverter>[] converters;
426      private final Class<? extends RestGuard>[] guards;
427      private final Class<? extends RestMatcher>[] matchers;
428      private final Class<? extends Encoder>[] encoders;
429      private final Class<? extends Serializer>[] serializers;
430      private final Class<?>[] parsers;
431      private final OpSwagger swagger;
432      private final String clientVersion, debug, defaultAccept, defaultCharset, defaultContentType, maxInput, method, rolesDeclared, roleGuard, summary, value;
433      private final String[] consumes, defaultRequestFormData, defaultRequestQueryData, defaultRequestAttributes, defaultRequestHeaders, defaultResponseHeaders, description, path, produces;
434
435      Impl(Builder b) {
436         super(b);
437         this.clientVersion = b.clientVersion;
438         this.consumes = copyOf(b.consumes);
439         this.converters = copyOf(b.converters);
440         this.debug = b.debug;
441         this.defaultAccept = b.defaultAccept;
442         this.defaultCharset = b.defaultCharset;
443         this.defaultContentType = b.defaultContentType;
444         this.defaultRequestFormData = copyOf(b.defaultRequestFormData);
445         this.defaultRequestQueryData = copyOf(b.defaultRequestQueryData);
446         this.defaultRequestAttributes = copyOf(b.defaultRequestAttributes);
447         this.defaultRequestHeaders = copyOf(b.defaultRequestHeaders);
448         this.defaultResponseHeaders = copyOf(b.defaultResponseHeaders);
449         this.description = copyOf(b.description);
450         this.encoders = copyOf(b.encoders);
451         this.guards = copyOf(b.guards);
452         this.matchers = copyOf(b.matchers);
453         this.maxInput = b.maxInput;
454         this.method = b.method;
455         this.parsers = copyOf(b.parsers);
456         this.path = copyOf(b.path);
457         this.produces = copyOf(b.produces);
458         this.roleGuard = b.roleGuard;
459         this.rolesDeclared = b.rolesDeclared;
460         this.serializers = copyOf(b.serializers);
461         this.summary = b.summary;
462         this.swagger = b.swagger;
463         this.value = b.value;
464         postConstruct();
465      }
466
467      @Override /* RestOp */
468      public String clientVersion() {
469         return clientVersion;
470      }
471
472      @Override /* RestOp */
473      public String[] consumes() {
474         return consumes;
475      }
476
477      @Override /* RestOp */
478      public Class<? extends RestConverter>[] converters() {
479         return converters;
480      }
481
482      @Override /* RestOp */
483      public String debug() {
484         return debug;
485      }
486
487      @Override /* RestOp */
488      public String defaultAccept() {
489         return defaultAccept;
490      }
491
492      @Override /* RestOp */
493      public String defaultCharset() {
494         return defaultCharset;
495      }
496
497      @Override /* RestOp */
498      public String defaultContentType() {
499         return defaultContentType;
500      }
501
502      @Override /* RestOp */
503      public String[] defaultRequestFormData() {
504         return defaultRequestFormData;
505      }
506
507      @Override /* RestOp */
508      public String[] defaultRequestQueryData() {
509         return defaultRequestQueryData;
510      }
511
512      @Override /* RestOp */
513      public String[] defaultRequestAttributes() {
514         return defaultRequestAttributes;
515      }
516
517      @Override /* RestOp */
518      public String[] defaultRequestHeaders() {
519         return defaultRequestHeaders;
520      }
521
522      @Override /* RestOp */
523      public String[] defaultResponseHeaders() {
524         return defaultResponseHeaders;
525      }
526
527      @Override /* RestOp */
528      public String[] description() {
529         return description;
530      }
531
532      @Override /* RestOp */
533      public Class<? extends Encoder>[] encoders() {
534         return encoders;
535      }
536
537      @Override /* RestOp */
538      public Class<? extends RestGuard>[] guards() {
539         return guards;
540      }
541
542      @Override /* RestOp */
543      public Class<? extends RestMatcher>[] matchers() {
544         return matchers;
545      }
546
547      @Override /* RestOp */
548      public String maxInput() {
549         return maxInput;
550      }
551
552      @Override /* RestOp */
553      public String method() {
554         return method;
555      }
556
557      @Override /* RestOp */
558      public Class<?>[] parsers() {
559         return parsers;
560      }
561
562      @Override /* RestOp */
563      public String[] path() {
564         return path;
565      }
566
567      @Override /* RestOp */
568      public String[] produces() {
569         return produces;
570      }
571
572      @Override /* RestOp */
573      public String roleGuard() {
574         return roleGuard;
575      }
576
577      @Override /* RestOp */
578      public String rolesDeclared() {
579         return rolesDeclared;
580      }
581
582      @Override /* RestOp */
583      public Class<? extends Serializer>[] serializers() {
584         return serializers;
585      }
586
587      @Override /* RestOp */
588      public String summary() {
589         return summary;
590      }
591
592      @Override /* RestOp */
593      public OpSwagger swagger() {
594         return swagger;
595      }
596
597      @Override /* RestOp */
598      public String value() {
599         return value;
600      }
601   }
602
603   //-----------------------------------------------------------------------------------------------------------------
604   // Appliers
605   //-----------------------------------------------------------------------------------------------------------------
606
607   /**
608    * Applies {@link RestOp} annotations to a {@link org.apache.juneau.rest.RestOpContext.Builder}.
609    */
610   public static class RestOpContextApply extends AnnotationApplier<RestOp,RestOpContext.Builder> {
611
612      /**
613       * Constructor.
614       *
615       * @param vr The resolver for resolving values in annotations.
616       */
617      public RestOpContextApply(VarResolverSession vr) {
618         super(RestOp.class, RestOpContext.Builder.class, vr);
619      }
620
621      @Override
622      public void apply(AnnotationInfo<RestOp> ai, RestOpContext.Builder b) {
623         RestOp a = ai.inner();
624
625         classes(a.serializers()).ifPresent(x -> b.serializers().set(x));
626         classes(a.parsers()).ifPresent(x -> b.parsers().set(x));
627         classes(a.encoders()).ifPresent(x -> b.encoders().set(x));
628         stream(a.produces()).map(MediaType::of).forEach(x -> b.produces(x));
629         stream(a.consumes()).map(MediaType::of).forEach(x -> b.consumes(x));
630         stream(a.defaultRequestHeaders()).map(HttpHeaders::stringHeader).forEach(x -> b.defaultRequestHeaders().setDefault(x));
631         stream(a.defaultResponseHeaders()).map(HttpHeaders::stringHeader).forEach(x -> b.defaultResponseHeaders().setDefault(x));
632         stream(a.defaultRequestAttributes()).map(BasicNamedAttribute::ofPair).forEach(x -> b.defaultRequestAttributes().add(x));
633         stream(a.defaultRequestQueryData()).map(HttpParts::basicPart).forEach(x -> b.defaultRequestQueryData().setDefault(x));
634         stream(a.defaultRequestFormData()).map(HttpParts::basicPart).forEach(x -> b.defaultRequestFormData().setDefault(x));
635         string(a.defaultAccept()).map(HttpHeaders::accept).ifPresent(x -> b.defaultRequestHeaders().setDefault(x));
636         string(a.defaultContentType()).map(HttpHeaders::contentType).ifPresent(x -> b.defaultRequestHeaders().setDefault(x));
637         b.converters().append(a.converters());
638         b.guards().append(a.guards());
639         b.matchers().append(a.matchers());
640         string(a.clientVersion()).ifPresent(x -> b.clientVersion(x));
641         string(a.defaultCharset()).map(Charset::forName).ifPresent(x -> b.defaultCharset(x));
642         string(a.maxInput()).ifPresent(x -> b.maxInput(x));
643         stream(a.path()).forEach(x -> b.path(x));
644         cdl(a.rolesDeclared()).forEach(x -> b.rolesDeclared(x));
645         string(a.roleGuard()).ifPresent(x -> b.roleGuard(x));
646
647         string(a.method()).ifPresent(x -> b.httpMethod(x));
648         string(a.debug()).map(Enablement::fromString).ifPresent(x -> b.debug(x));
649
650         String v = StringUtils.trim(string(a.value()).orElse(null));
651         if (v != null) {
652            int i = v.indexOf(' ');
653            if (i == -1) {
654               b.httpMethod(v);
655            } else {
656               b.httpMethod(v.substring(0, i).trim());
657               b.path(v.substring(i).trim());
658            }
659         }
660      }
661   }
662}