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.http.annotation;
014
015import static java.lang.annotation.ElementType.*;
016import static java.lang.annotation.RetentionPolicy.*;
017import static org.apache.juneau.common.internal.StringUtils.*;
018import static org.apache.juneau.internal.ArrayUtils.*;
019
020import java.lang.annotation.*;
021import java.lang.reflect.*;
022
023import org.apache.juneau.*;
024import org.apache.juneau.annotation.*;
025import org.apache.juneau.httppart.*;
026import org.apache.juneau.reflect.*;
027import org.apache.juneau.svl.*;
028
029/**
030 * Utility classes and methods for the {@link Header @Header} annotation.
031 *
032 * <h5 class='section'>See Also:</h5><ul>
033 * </ul>
034 */
035public class HeaderAnnotation {
036
037   //-----------------------------------------------------------------------------------------------------------------
038   // Static
039   //-----------------------------------------------------------------------------------------------------------------
040
041   /** Default value */
042   public static final Header DEFAULT = create().build();
043
044   /**
045    * Instantiates a new builder for this class.
046    *
047    * @return A new builder object.
048    */
049   public static Builder create() {
050      return new Builder();
051   }
052
053   /**
054    * Instantiates a new builder for this class.
055    *
056    * @param on The targets this annotation applies to.
057    * @return A new builder object.
058    */
059   public static Builder create(Class<?>...on) {
060      return create().on(on);
061   }
062
063   /**
064    * Instantiates a new builder for this class.
065    *
066    * @param on The targets this annotation applies to.
067    * @return A new builder object.
068    */
069   public static Builder create(String...on) {
070      return create().on(on);
071   }
072
073   /**
074    * Returns <jk>true</jk> if the specified annotation contains all default values.
075    *
076    * @param a The annotation to check.
077    * @return <jk>true</jk> if the specified annotation contains all default values.
078    */
079   public static boolean empty(Header a) {
080      return a == null || DEFAULT.equals(a);
081   }
082
083   /**
084    * Finds the name from the specified lists of annotations.
085    *
086    * <p>
087    * The last matching name found is returned.
088    *
089    * @param pi The parameter.
090    * @return The last matching name, or {@link Value#empty()} if not found.
091    */
092   public static Value<String> findName(ParamInfo pi) {
093      Value<String> n = Value.empty();
094      pi.forEachAnnotation(Header.class, x -> isNotEmpty(x.value()), x -> n.set(x.value()));
095      pi.forEachAnnotation(Header.class, x -> isNotEmpty(x.name()), x -> n.set(x.name()));
096      return n;
097   }
098
099   /**
100    * Finds the default value from the specified list of annotations.
101    *
102    * @param pi The parameter.
103    * @return The last matching default value, or {@link Value#empty()} if not found.
104    */
105   public static Value<String> findDef(ParamInfo pi) {
106      Value<String> n = Value.empty();
107      pi.forEachAnnotation(Header.class, x -> isNotEmpty(x.def()), x -> n.set(x.def()));
108      return n;
109   }
110
111   //-----------------------------------------------------------------------------------------------------------------
112   // Builder
113   //-----------------------------------------------------------------------------------------------------------------
114
115   /**
116    * Builder class.
117    *
118    * <h5 class='section'>See Also:</h5><ul>
119    *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)}
120    * </ul>
121    */
122   public static class Builder extends TargetedAnnotationTMFBuilder {
123
124      Class<? extends HttpPartParser> parser = HttpPartParser.Void.class;
125      Class<? extends HttpPartSerializer> serializer = HttpPartSerializer.Void.class;
126      Schema schema = SchemaAnnotation.DEFAULT;
127      String name="", value="", def="";
128
129      /**
130       * Constructor.
131       */
132      protected Builder() {
133         super(Header.class);
134      }
135
136      /**
137       * Instantiates a new {@link Header @Header} object initialized with this builder.
138       *
139       * @return A new {@link Header @Header} object.
140       */
141      public Header build() {
142         return new Impl(this);
143      }
144
145      /**
146       * Sets the {@link Header#def} property on this annotation.
147       *
148       * @param value The new value for this property.
149       * @return This object.
150       */
151      public Builder def(String value) {
152         this.def = value;
153         return this;
154      }
155
156      /**
157       * Sets the {@link Header#name} property on this annotation.
158       *
159       * @param value The new value for this property.
160       * @return This object.
161       */
162      public Builder name(String value) {
163         this.name = value;
164         return this;
165      }
166
167      /**
168       * Sets the {@link Header#parser} property on this annotation.
169       *
170       * @param value The new value for this property.
171       * @return This object.
172       */
173      public Builder parser(Class<? extends HttpPartParser> value) {
174         this.parser = value;
175         return this;
176      }
177
178      /**
179       * Sets the {@link Header#schema} property on this annotation.
180       *
181       * @param value The new value for this property.
182       * @return This object.
183       */
184      public Builder schema(Schema value) {
185         this.schema = value;
186         return this;
187      }
188
189      /**
190       * Sets the {@link Header#serializer} property on this annotation.
191       *
192       * @param value The new value for this property.
193       * @return This object.
194       */
195      public Builder serializer(Class<? extends HttpPartSerializer> value) {
196         this.serializer = value;
197         return this;
198      }
199
200      /**
201       * Sets the {@link Header#value} property on this annotation.
202       *
203       * @param value The new value for this property.
204       * @return This object.
205       */
206      public Builder value(String value) {
207         this.value = value;
208         return this;
209      }
210
211      // <FluentSetters>
212
213      @Override /* GENERATED - TargetedAnnotationBuilder */
214      public Builder on(String...values) {
215         super.on(values);
216         return this;
217      }
218
219      @Override /* GENERATED - TargetedAnnotationTBuilder */
220      public Builder on(java.lang.Class<?>...value) {
221         super.on(value);
222         return this;
223      }
224
225      @Override /* GENERATED - TargetedAnnotationTBuilder */
226      public Builder onClass(java.lang.Class<?>...value) {
227         super.onClass(value);
228         return this;
229      }
230
231      @Override /* GENERATED - TargetedAnnotationTMFBuilder */
232      public Builder on(Field...value) {
233         super.on(value);
234         return this;
235      }
236
237      @Override /* GENERATED - TargetedAnnotationTMFBuilder */
238      public Builder on(Method...value) {
239         super.on(value);
240         return this;
241      }
242
243      // </FluentSetters>
244   }
245
246   //-----------------------------------------------------------------------------------------------------------------
247   // Implementation
248   //-----------------------------------------------------------------------------------------------------------------
249
250   private static class Impl extends TargetedAnnotationTImpl implements Header {
251
252      private final Class<? extends HttpPartParser> parser;
253      private final Class<? extends HttpPartSerializer> serializer;
254      private final String name, value, def;
255      private final Schema schema;
256
257      Impl(Builder b) {
258         super(b);
259         this.def = b.def;
260         this.name = b.name;
261         this.parser = b.parser;
262         this.schema = b.schema;
263         this.serializer = b.serializer;
264         this.value = b.value;
265         postConstruct();
266      }
267
268      @Override /* Header */
269      public String def() {
270         return def;
271      }
272
273      @Override /* Header */
274      public String name() {
275         return name;
276      }
277
278      @Override /* Header */
279      public Class<? extends HttpPartParser> parser() {
280         return parser;
281      }
282
283      @Override /* Header */
284      public Schema schema() {
285         return schema;
286      }
287
288      @Override /* Header */
289      public Class<? extends HttpPartSerializer> serializer() {
290         return serializer;
291      }
292
293      @Override /* Header */
294      public String value() {
295         return value;
296      }
297   }
298
299   //-----------------------------------------------------------------------------------------------------------------
300   // Appliers
301   //-----------------------------------------------------------------------------------------------------------------
302
303   /**
304    * Applies targeted {@link Header} annotations to a {@link org.apache.juneau.BeanContext.Builder}.
305    */
306   public static class Applier extends AnnotationApplier<Header,BeanContext.Builder> {
307
308      /**
309       * Constructor.
310       *
311       * @param vr The resolver for resolving values in annotations.
312       */
313      public Applier(VarResolverSession vr) {
314         super(Header.class, BeanContext.Builder.class, vr);
315      }
316
317      @Override
318      public void apply(AnnotationInfo<Header> ai, BeanContext.Builder b) {
319         Header a = ai.inner();
320         if (isEmptyArray(a.on(), a.onClass()))
321            return;
322         b.annotations(a);
323      }
324   }
325
326   //-----------------------------------------------------------------------------------------------------------------
327   // Other
328   //-----------------------------------------------------------------------------------------------------------------
329
330   /**
331    * A collection of {@link Header @Header annotations}.
332    */
333   @Documented
334   @Target({METHOD,TYPE})
335   @Retention(RUNTIME)
336   @Inherited
337   public static @interface Array {
338
339      /**
340       * The child annotations.
341       *
342       * @return The annotation value.
343       */
344      Header[] value();
345   }
346}