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