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.commons.utils.ClassUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.StringUtils.*;
022import static org.apache.juneau.commons.utils.ThrowableUtils.*;
023import static org.apache.juneau.commons.utils.Utils.*;
024import static org.apache.juneau.http.HttpHeaders.*;
025
026import java.lang.reflect.*;
027import java.util.*;
028
029import org.apache.juneau.commons.reflect.*;
030import org.apache.juneau.http.header.*;
031import org.apache.juneau.http.remote.*;
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 static String resolve(String s) {
049      return VarResolver.DEFAULT.resolve(s);
050   }
051
052   private final Map<Method,RemoteOperationMeta> operations;
053
054   private final HeaderList headers;
055
056   /**
057    * Constructor.
058    *
059    * @param c The interface class annotated with a {@link org.apache.juneau.http.remote.Remote @Remote} annotation (optional).
060    */
061   public RemoteMeta(Class<?> c) {
062      var path = "";
063
064      var ci = ClassInfo.of(c);
065      var remotes = rstream(ci.getAnnotations(Remote.class).toList()).map(AnnotationInfo::inner).toList();
066
067      var versionHeader = "Client-Version";
068      var clientVersion = (String)null;
069      var headers = HeaderList.create().resolving();
070
071      for (var r : remotes) {
072         if (ne(r.path()))
073            path = trimSlashes(resolve(r.path()));
074         for (var h : r.headers())
075            headers.append(stringHeader(resolve(h)));
076         if (ne(r.version()))
077            clientVersion = resolve(r.version());
078         if (ne(r.versionHeader()))
079            versionHeader = resolve(r.versionHeader());
080         if (isNotVoid(r.headerList())) {
081            try {
082               headers.append(r.headerList().getDeclaredConstructor().newInstance().getAll());
083            } catch (Exception e) {
084               throw rex(e, "Could not instantiate HeaderSupplier class");
085            }
086         }
087      }
088
089      if (nn(clientVersion))
090         headers.append(stringHeader(versionHeader, clientVersion));
091
092      Map<Method,RemoteOperationMeta> operations = map();
093      var path2 = path;
094      ci.getPublicMethods().stream().forEach(x -> operations.put(x.inner(), new RemoteOperationMeta(path2, x.inner(), "GET")));
095
096      this.operations = u(operations);
097      this.headers = headers;
098   }
099
100   /**
101    * Returns the headers to set on all requests.
102    *
103    * @return The headers to set on all requests.
104    */
105   public HeaderList getHeaders() { return headers; }
106
107   /**
108    * Returns the metadata about the specified operation on this resource proxy.
109    *
110    * @param m The method to look up.
111    * @return Metadata about the method or <jk>null</jk> if no metadata was found.
112    */
113   public RemoteOperationMeta getOperationMeta(Method m) {
114      return operations.get(m);
115   }
116}