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.rest.client.remote;
018
019import static org.apache.juneau.common.utils.Utils.*;
020import static org.apache.juneau.http.HttpHeaders.*;
021import static org.apache.juneau.internal.ClassUtils.*;
022import static org.apache.juneau.internal.CollectionUtils.map;
023
024import java.lang.reflect.*;
025import java.util.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.common.utils.*;
029import org.apache.juneau.http.header.*;
030import org.apache.juneau.http.remote.*;
031import org.apache.juneau.reflect.*;
032import org.apache.juneau.svl.*;
033
034/**
035 * Contains the meta-data about a REST proxy class.
036 *
037 * <p>
038 * Captures the information in {@link org.apache.juneau.http.remote.Remote @Remote} and {@link org.apache.juneau.http.remote.RemoteOp @RemoteOp} annotations for
039 * caching and reuse.
040 *
041 * <h5 class='section'>See Also:</h5><ul>
042 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestProxyBasics">REST Proxy Basics</a>
043 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestClientBasics">juneau-rest-client Basics</a>
044 * </ul>
045 */
046public class RemoteMeta {
047
048   private final Map<Method,RemoteOperationMeta> operations;
049   private final HeaderList headers;
050
051   /**
052    * Constructor.
053    *
054    * @param c The interface class annotated with a {@link org.apache.juneau.http.remote.Remote @Remote} annotation (optional).
055    */
056   public RemoteMeta(Class<?> c) {
057      String path = "";
058
059      ClassInfo ci = ClassInfo.of(c);
060      List<Remote> remotes = ci.getAnnotations(Remote.class);
061
062      String versionHeader = "Client-Version", clientVersion = null;
063      HeaderList headers = HeaderList.create().resolving();
064
065      for (Remote r : remotes) {
066         if (isNotEmpty(r.path()))
067            path = StringUtils.trimSlashes(resolve(r.path()));
068         for (String h : r.headers())
069            headers.append(stringHeader(resolve(h)));
070         if (isNotEmpty(r.version()))
071            clientVersion = resolve(r.version());
072         if (isNotEmpty(r.versionHeader()))
073            versionHeader = resolve(r.versionHeader());
074         if (isNotVoid(r.headerList())) {
075            try {
076               headers.append(r.headerList().getDeclaredConstructor().newInstance().getAll());
077            } catch (Exception e) {
078               throw new BasicRuntimeException(e, "Could not instantiate HeaderSupplier class");
079            }
080         }
081      }
082
083      if (clientVersion != null)
084         headers.append(stringHeader(versionHeader, clientVersion));
085
086      Map<Method,RemoteOperationMeta> operations = map();
087      String path2 = path;
088      ci.forEachPublicMethod(
089         x -> true,
090         x -> operations.put(x.inner(), new RemoteOperationMeta(path2, x.inner(), "GET"))
091      );
092
093      this.operations = u(operations);
094      this.headers = headers;
095   }
096
097   /**
098    * Returns the metadata about the specified operation on this resource proxy.
099    *
100    * @param m The method to look up.
101    * @return Metadata about the method or <jk>null</jk> if no metadata was found.
102    */
103   public RemoteOperationMeta getOperationMeta(Method m) {
104      return operations.get(m);
105   }
106
107   /**
108    * Returns the headers to set on all requests.
109    *
110    * @return The headers to set on all requests.
111    */
112   public HeaderList getHeaders() {
113      return headers;
114   }
115
116   //------------------------------------------------------------------------------------------------------------------
117   // Helper methods.
118   //------------------------------------------------------------------------------------------------------------------
119
120   private static String resolve(String s) {
121      return VarResolver.DEFAULT.resolve(s);
122   }
123}