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