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