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