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