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