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.remoteable;
014
015import static org.apache.juneau.internal.ClassUtils.*;
016import static org.apache.juneau.internal.StringUtils.*;
017
018import java.lang.annotation.*;
019import java.lang.reflect.*;
020import java.util.*;
021
022/**
023 * @deprecated Internal class.
024 */
025@Deprecated
026public class RemoteableMethodMeta {
027
028   private final String httpMethod;
029   private final String url;
030   private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, formDataArgs, requestBeanArgs;
031   private final Integer[] otherArgs;
032   private final Integer bodyArg;
033   private final ReturnValue returnValue;
034
035   /**
036    * Constructor.
037    *
038    * @param restUrl The absolute URL of the REST interface backing the interface proxy.
039    * @param m The Java method.
040    */
041   public RemoteableMethodMeta(final String restUrl, Method m) {
042      Builder b = new Builder(restUrl, m);
043      this.httpMethod = b.httpMethod;
044      this.url = b.url;
045      this.pathArgs = b.pathArgs.toArray(new RemoteMethodArg[b.pathArgs.size()]);
046      this.queryArgs = b.queryArgs.toArray(new RemoteMethodArg[b.queryArgs.size()]);
047      this.formDataArgs = b.formDataArgs.toArray(new RemoteMethodArg[b.formDataArgs.size()]);
048      this.headerArgs = b.headerArgs.toArray(new RemoteMethodArg[b.headerArgs.size()]);
049      this.requestBeanArgs = b.requestBeanArgs.toArray(new RemoteMethodArg[b.requestBeanArgs.size()]);
050      this.otherArgs = b.otherArgs.toArray(new Integer[b.otherArgs.size()]);
051      this.bodyArg = b.bodyArg;
052      this.returnValue = b.returnValue;
053   }
054
055   private static final class Builder {
056      String httpMethod, url;
057      List<RemoteMethodArg>
058         pathArgs = new LinkedList<>(),
059         queryArgs = new LinkedList<>(),
060         headerArgs = new LinkedList<>(),
061         formDataArgs = new LinkedList<>(),
062         requestBeanArgs = new LinkedList<>();
063      List<Integer>
064         otherArgs = new LinkedList<>();
065      Integer bodyArg;
066      ReturnValue returnValue;
067
068      Builder(String restUrl, Method m) {
069         Remoteable r = m.getDeclaringClass().getAnnotation(Remoteable.class);
070         RemoteMethod rm = m.getAnnotation(RemoteMethod.class);
071
072         httpMethod = rm == null ? "POST" : rm.httpMethod();
073         if (! isOneOf(httpMethod, "DELETE", "GET", "POST", "PUT"))
074            throw new RemoteableMetadataException(m,
075               "Invalid value specified for @RemoteMethod.httpMethod() annotation.  Valid values are [DELTE,GET,POST,PUT].");
076
077         String path = rm == null || rm.path().isEmpty() ? null : rm.path();
078         String methodPaths = r == null ? "NAME" : r.methodPaths();
079
080         if (! isOneOf(methodPaths, "NAME", "SIGNATURE"))
081            throw new RemoteableMetadataException(m,
082               "Invalid value specified for @Remoteable.methodPaths() annotation.  Valid values are [NAME,SIGNATURE].");
083
084         returnValue = rm == null ? ReturnValue.BODY : rm.returns();
085
086         url =
087            trimSlashes(restUrl)
088            + '/'
089            + (path != null ? trimSlashes(path) : urlEncode("NAME".equals(methodPaths) ? m.getName() : getMethodSignature(m)));
090
091         int index = 0;
092         for (Annotation[] aa : m.getParameterAnnotations()) {
093            boolean annotated = false;
094            for (Annotation a : aa) {
095               Class<?> ca = a.annotationType();
096               if (ca == Path.class) {
097                  Path p = (Path)a;
098                  annotated = pathArgs.add(new RemoteMethodArg(p.name(), p.value(), index, false, p.serializer()));
099               } else if (ca == Query.class) {
100                  Query q = (Query)a;
101                  annotated = queryArgs.add(new RemoteMethodArg(q.name(), q.value(), index, q.skipIfEmpty(), q.serializer()));
102               } else if (ca == QueryIfNE.class) {
103                  QueryIfNE q = (QueryIfNE)a;
104                  annotated = queryArgs.add(new RemoteMethodArg(q.name(), q.value(), index, true, q.serializer()));
105               } else if (ca == FormData.class) {
106                  FormData f = (FormData)a;
107                  annotated = formDataArgs.add(new RemoteMethodArg(f.name(), f.value(), index, f.skipIfEmpty(), f.serializer()));
108               } else if (ca == FormDataIfNE.class) {
109                  FormDataIfNE f = (FormDataIfNE)a;
110                  annotated = formDataArgs.add(new RemoteMethodArg(f.name(), f.value(), index, true, f.serializer()));
111               } else if (ca == Header.class) {
112                  Header h = (Header)a;
113                  annotated = headerArgs.add(new RemoteMethodArg(h.name(), h.value(), index, h.skipIfEmpty(), h.serializer()));
114               } else if (ca == HeaderIfNE.class) {
115                  HeaderIfNE h = (HeaderIfNE)a;
116                  annotated = headerArgs.add(new RemoteMethodArg(h.name(), h.value(), index, true, h.serializer()));
117               } else if (ca == RequestBean.class) {
118                  RequestBean rb = (RequestBean)a;
119                  annotated = requestBeanArgs.add(new RemoteMethodArg("", "", index, false, rb.serializer()));
120               } else if (ca == Body.class) {
121                  annotated = true;
122                  if (bodyArg == null)
123                     bodyArg = index;
124                  else
125                     throw new RemoteableMetadataException(m,
126                        "Multiple @Body parameters found.  Only one can be specified per Java method.");
127               }
128            }
129            if (! annotated)
130               otherArgs.add(index);
131            index++;
132         }
133
134         if (bodyArg != null && otherArgs.size() > 0)
135            throw new RemoteableMetadataException(m,
136               "@Body and non-annotated parameters found together.  Non-annotated parameters cannot be used when @Body is used.");
137      }
138   }
139
140   /**
141    * Returns the value of the {@link RemoteMethod#httpMethod() @RemoteMethod.httpMethod()} annotation on this Java method.
142    *
143    * @return The value of the annotation, never <jk>null</jk>.
144    */
145   public String getHttpMethod() {
146      return httpMethod;
147   }
148
149   /**
150    * Returns the absolute URL of the REST interface invoked by this Java method.
151    *
152    * @return The absolute URL of the REST interface, never <jk>null</jk>.
153    */
154   public String getUrl() {
155      return url;
156   }
157
158   /**
159    * Returns the {@link Path @Path} annotated arguments on this Java method.
160    *
161    * @return A map of {@link Path#value() @Path.value()} names to zero-indexed argument indices.
162    */
163   public RemoteMethodArg[] getPathArgs() {
164      return pathArgs;
165   }
166
167   /**
168    * Returns the {@link Query @Query} annotated arguments on this Java method.
169    *
170    * @return A map of {@link Query#value() @Query.value()} names to zero-indexed argument indices.
171    */
172   public RemoteMethodArg[] getQueryArgs() {
173      return queryArgs;
174   }
175
176   /**
177    * Returns the {@link FormData @FormData} annotated arguments on this Java method.
178    *
179    * @return A map of {@link FormData#value() @FormData.value()} names to zero-indexed argument indices.
180    */
181   public RemoteMethodArg[] getFormDataArgs() {
182      return formDataArgs;
183   }
184
185   /**
186    * Returns the {@link Header @Header} annotated arguments on this Java method.
187    *
188    * @return A map of {@link Header#value() @Header.value()} names to zero-indexed argument indices.
189    */
190   public RemoteMethodArg[] getHeaderArgs() {
191      return headerArgs;
192   }
193
194   /**
195    * Returns the {@link RequestBean @RequestBean} annotated arguments on this Java method.
196    *
197    * @return A list of zero-indexed argument indices.
198    */
199   public RemoteMethodArg[] getRequestBeanArgs() {
200      return requestBeanArgs;
201   }
202
203   /**
204    * Returns the remaining non-annotated arguments on this Java method.
205    *
206    * @return A list of zero-indexed argument indices.
207    */
208   public Integer[] getOtherArgs() {
209      return otherArgs;
210   }
211
212   /**
213    * Returns the argument annotated with {@link Body @Body}.
214    *
215    * @return A index of the argument with the {@link Body @Body} annotation, or <jk>null</jk> if no argument exists.
216    */
217   public Integer getBodyArg() {
218      return bodyArg;
219   }
220
221   /**
222    * Returns whether the method returns the HTTP response body or status code.
223    *
224    * @return Whether the method returns the HTTP response body or status code.
225    */
226   public ReturnValue getReturns() {
227      return returnValue;
228   }
229}