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