1 /*
2  * Copyright 2017 Google LLC
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google LLC nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 package com.google.api.gax.rpc;
31 
32 import com.google.api.gax.core.GaxProperties;
33 import com.google.common.collect.ImmutableMap;
34 import java.io.Serializable;
35 import java.util.Map;
36 
37 /**
38  * Implementation of HeaderProvider that provides headers describing the API client library making
39  * API calls.
40  */
41 public class ApiClientHeaderProvider implements HeaderProvider, Serializable {
42   private static final long serialVersionUID = -8876627296793342119L;
43   static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project";
44 
45   private final Map<String, String> headers;
46 
ApiClientHeaderProvider(Builder builder)47   protected ApiClientHeaderProvider(Builder builder) {
48     ImmutableMap.Builder<String, String> headersBuilder = ImmutableMap.builder();
49 
50     if (builder.getApiClientHeaderKey() != null) {
51       StringBuilder apiClientHeaderValue = new StringBuilder();
52       // Order of tokens matters!!!
53       appendToken(apiClientHeaderValue, builder.getJvmToken());
54       appendToken(apiClientHeaderValue, builder.getClientLibToken());
55       appendToken(apiClientHeaderValue, builder.getGeneratedLibToken());
56       appendToken(apiClientHeaderValue, builder.getGeneratedRuntimeToken());
57       appendToken(apiClientHeaderValue, builder.getTransportToken());
58       if (apiClientHeaderValue.length() > 0) {
59         headersBuilder.put(builder.getApiClientHeaderKey(), apiClientHeaderValue.toString());
60       }
61     }
62 
63     if (builder.getResourceHeaderKey() != null && builder.getResourceToken() != null) {
64       headersBuilder.put(builder.getResourceHeaderKey(), builder.getResourceToken());
65     }
66 
67     if (builder.getQuotaProjectIdToken() != null) {
68       headersBuilder.put(QUOTA_PROJECT_ID_HEADER_KEY, builder.getQuotaProjectIdToken());
69     }
70 
71     this.headers = headersBuilder.build();
72   }
73 
74   @Override
getHeaders()75   public Map<String, String> getHeaders() {
76     return headers;
77   }
78 
appendToken(StringBuilder sb, String token)79   protected static void appendToken(StringBuilder sb, String token) {
80     if (token != null) {
81       if (sb.length() > 0) {
82         sb.append(' ');
83       }
84       sb.append(token);
85     }
86   }
87 
newBuilder()88   public static Builder newBuilder() {
89     return new Builder();
90   }
91 
getDefaultApiClientHeaderKey()92   public static String getDefaultApiClientHeaderKey() {
93     return "x-goog-api-client";
94   }
95 
getDefaultResourceHeaderKey()96   public static String getDefaultResourceHeaderKey() {
97     return "google-cloud-resource-prefix";
98   }
99 
100   public static class Builder {
101     private String apiClientHeaderKey;
102     private String jvmToken;
103     private String clientLibToken;
104     private String generatedLibToken;
105     private String generatedRuntimeToken;
106     private String transportToken;
107     private String quotaProjectIdToken;
108 
109     private String resourceHeaderKey;
110     private String resourceToken;
111 
Builder()112     protected Builder() {
113       // Initialize with default values
114       apiClientHeaderKey = getDefaultApiClientHeaderKey();
115       setJvmToken(GaxProperties.getJavaVersion());
116       clientLibToken = null;
117       generatedLibToken = null;
118       setClientRuntimeToken(GaxProperties.getGaxVersion());
119       transportToken = null;
120       quotaProjectIdToken = null;
121 
122       resourceHeaderKey = getDefaultResourceHeaderKey();
123       resourceToken = null;
124     }
125 
getApiClientHeaderKey()126     public String getApiClientHeaderKey() {
127       return apiClientHeaderKey;
128     }
129 
setApiClientHeaderKey(String apiClientHeaderKey)130     public Builder setApiClientHeaderKey(String apiClientHeaderKey) {
131       this.apiClientHeaderKey = apiClientHeaderKey;
132       return this;
133     }
134 
getJvmToken()135     public String getJvmToken() {
136       return jvmToken;
137     }
138 
setJvmToken(String version)139     public Builder setJvmToken(String version) {
140       this.jvmToken = constructToken("gl-java", version);
141       return this;
142     }
143 
getClientLibToken()144     public String getClientLibToken() {
145       return clientLibToken;
146     }
147 
setClientLibToken(String name, String version)148     public Builder setClientLibToken(String name, String version) {
149       this.clientLibToken = constructToken(name, version);
150       return this;
151     }
152 
getGeneratedLibToken()153     public String getGeneratedLibToken() {
154       return generatedLibToken;
155     }
156 
setGeneratedLibToken(String name, String version)157     public Builder setGeneratedLibToken(String name, String version) {
158       this.generatedLibToken = constructToken(name, version);
159       return this;
160     }
161 
getGeneratedRuntimeToken()162     public String getGeneratedRuntimeToken() {
163       return generatedRuntimeToken;
164     }
165 
setClientRuntimeToken(String version)166     public Builder setClientRuntimeToken(String version) {
167       this.generatedRuntimeToken = constructToken("gax", version);
168       return this;
169     }
170 
getTransportToken()171     public String getTransportToken() {
172       return transportToken;
173     }
174 
setTransportToken(String name, String version)175     public Builder setTransportToken(String name, String version) {
176       this.transportToken = constructToken(name, version);
177       return this;
178     }
179 
180     /** @return the quotaProjectIdToken used for quota and billing purposes. */
getQuotaProjectIdToken()181     public String getQuotaProjectIdToken() {
182       return quotaProjectIdToken;
183     }
184 
185     /** Sets the project ID used for quota and billing purposes. */
setQuotaProjectIdToken(String quotaProjectIdToken)186     public Builder setQuotaProjectIdToken(String quotaProjectIdToken) {
187       this.quotaProjectIdToken = quotaProjectIdToken;
188       return this;
189     }
190 
getResourceHeaderKey()191     public String getResourceHeaderKey() {
192       return resourceHeaderKey;
193     }
194 
setResourceHeaderKey(String resourceHeaderKey)195     public Builder setResourceHeaderKey(String resourceHeaderKey) {
196       this.resourceHeaderKey = resourceHeaderKey;
197       return this;
198     }
199 
getResourceToken()200     public String getResourceToken() {
201       return resourceToken;
202     }
203 
setResourceToken(String resourceToken)204     public Builder setResourceToken(String resourceToken) {
205       this.resourceToken = resourceToken;
206       return this;
207     }
208 
constructToken(String name, String version)209     private String constructToken(String name, String version) {
210       if (version == null) {
211         return null;
212       }
213       if (name == null) {
214         throw new IllegalArgumentException("Token name cannot be null");
215       }
216       return name + '/' + version;
217     }
218 
build()219     public ApiClientHeaderProvider build() {
220       return new ApiClientHeaderProvider(this);
221     }
222   }
223 }
224