Skip to content

Commit 08b69f1

Browse files
committed
Rebuilt local RequestOptions class and improved headers
Also adds more control over headers, including User-Agent, X-Elastic-Client-Meta and custom headers.
1 parent 948c23b commit 08b69f1

File tree

14 files changed

+1294
-31
lines changed

14 files changed

+1294
-31
lines changed
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package co.elastic.clients.base;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
import java.util.Properties;
27+
28+
/**
29+
* This class models a set of client metadata, including Elasticsearch
30+
* version, Java platform version and {@link Transport} version. This
31+
* information is typically compiled into a header field called
32+
* {@code X-Elastic-Client-Meta} and sent to the server with each request.
33+
*
34+
* TODO: optional fields beyond "es", "jv" and "t"
35+
*
36+
* @see <a href="https://github.com/elastic/clients-team/blob/master/knowledgebase/specifications/client-meta-header.md">
37+
* Structured HTTP Header for Client Metadata</a>
38+
*/
39+
public class ClientMetadata implements ConvertibleToHeader {
40+
41+
/**
42+
* Location of the properties file containing project
43+
* version metadata.
44+
*/
45+
private static final String VERSION_PROPERTIES = "/co.elastic.clients.elasticsearch/version.properties";
46+
47+
/**
48+
* Empty static instance of {@link ClientMetadata} used to
49+
* disable sending the X-Elastic-Client-Meta header.
50+
*/
51+
public static final ClientMetadata EMPTY = new ClientMetadata();
52+
53+
/**
54+
* Construct an instance of {@link ClientMetadata} containing
55+
* versions of components currently in use. This will be the
56+
* method generally used in a production context for
57+
* obtaining an instance of this class.
58+
*
59+
* @return {@link ClientMetadata} instance
60+
*/
61+
public static ClientMetadata forLocalSystem() {
62+
Version esVersion = getElasticsearchVersion();
63+
return new Builder()
64+
.withElasticsearchVersion(esVersion)
65+
.withJavaVersion(getJavaVersion())
66+
.withTransportVersion(esVersion)
67+
.build();
68+
}
69+
70+
/**
71+
* Builder for constructing {@link ClientMetadata} instances.
72+
* This exists mainly for use in a non-production context.
73+
*/
74+
public static class Builder {
75+
76+
private Version elasticsearchVersion;
77+
private Version javaVersion;
78+
private Version transportVersion;
79+
80+
public Builder() {
81+
elasticsearchVersion = null;
82+
javaVersion = null;
83+
transportVersion = null;
84+
}
85+
86+
public Builder withElasticsearchVersion(Version version) {
87+
elasticsearchVersion = version;
88+
return this;
89+
}
90+
91+
public Builder withJavaVersion(Version version) {
92+
javaVersion = version;
93+
return this;
94+
}
95+
96+
public Builder withTransportVersion(Version version) {
97+
transportVersion = version;
98+
return this;
99+
}
100+
101+
public ClientMetadata build() {
102+
return new ClientMetadata(
103+
elasticsearchVersion,
104+
javaVersion,
105+
transportVersion);
106+
}
107+
108+
}
109+
110+
private final Version elasticsearchVersion;
111+
private final Version javaVersion;
112+
private final Version transportVersion;
113+
114+
/**
115+
* The class constructor is private, as it is intended for
116+
* instances to be constructed via the {@link Builder} or
117+
* the {@link #forLocalSystem()} method.
118+
*
119+
* @param elasticsearchVersion {@link Version} of Elasticsearch
120+
* @param javaVersion {@link Version} of the Java platform
121+
* @param transportVersion {@link Version} of {@link Transport}
122+
*/
123+
private ClientMetadata(Version elasticsearchVersion, Version javaVersion, Version transportVersion) {
124+
if (elasticsearchVersion == null) {
125+
throw new IllegalArgumentException("Elasticsearch version may not be omitted from client metadata");
126+
}
127+
else {
128+
this.elasticsearchVersion = elasticsearchVersion;
129+
}
130+
if (javaVersion == null) {
131+
throw new IllegalArgumentException("Java version may not be omitted from client metadata");
132+
}
133+
else {
134+
this.javaVersion = javaVersion;
135+
}
136+
if (transportVersion == null) {
137+
throw new IllegalArgumentException("Transport version may not be omitted from client metadata");
138+
}
139+
else {
140+
this.transportVersion = transportVersion;
141+
}
142+
}
143+
144+
/**
145+
* Separate constructor used for the {@link #EMPTY} instance.
146+
*/
147+
private ClientMetadata() {
148+
this.elasticsearchVersion = null;
149+
this.javaVersion = null;
150+
this.transportVersion = null;
151+
}
152+
153+
/**
154+
* {@link Version} of Elasticsearch represented by this metadata.
155+
*
156+
* @return Elasticsearch {@link Version}
157+
*/
158+
public Version elasticsearchVersion() {
159+
return elasticsearchVersion;
160+
}
161+
162+
/**
163+
* {@link Version} of the Java platform represented by this metadata.
164+
*
165+
* @return Java platform {@link Version}
166+
*/
167+
public Version javaVersion() {
168+
return javaVersion;
169+
}
170+
171+
/**
172+
* {@link Version} of {@link Transport} represented by this metadata.
173+
*
174+
* @return {@link Transport} {@link Version}
175+
*/
176+
public Version transportVersion() {
177+
return transportVersion;
178+
}
179+
180+
@Override
181+
public String toString() {
182+
return String.join(",", pairStrings());
183+
}
184+
185+
/**
186+
* Construct a list of "key=value" strings for all
187+
* non-null values.
188+
*
189+
* @return list of strings
190+
*/
191+
private List<String> pairStrings() {
192+
List<String> bits = new ArrayList<>();
193+
if (elasticsearchVersion != null) {
194+
bits.add("es=" + elasticsearchVersion);
195+
}
196+
if (javaVersion != null) {
197+
bits.add("jv=" + javaVersion);
198+
}
199+
if (transportVersion != null) {
200+
bits.add("t=" + transportVersion);
201+
}
202+
return bits;
203+
}
204+
205+
/**
206+
* Convert this client metadata instance into a {@link Header}
207+
* for inclusion in an HTTP request.
208+
*
209+
* The resulting {@link Header#value()} may be null, which denotes
210+
* that metadata tracking should be disabled.
211+
*
212+
* @return {@code X-Elastic-Client-Meta} {@link Header}
213+
*/
214+
@Override
215+
public Header toHeader() {
216+
// According to the spec, "There must be at least one key-value
217+
// pair if the header is added to a request. An empty header
218+
// is not valid."
219+
//
220+
// To that end, if no key-value pairs have been populated, we
221+
// return a null-valued header which will be excluded from the
222+
// headers, disabling client metadata.
223+
if (this.pairStrings().size() == 0) {
224+
return Header.raw("X-Elastic-Client-Meta", null);
225+
}
226+
else {
227+
return Header.raw("X-Elastic-Client-Meta", this);
228+
}
229+
}
230+
231+
/**
232+
* Fetch and return Java version information as a
233+
* {@link Version} object.
234+
*
235+
* @return Java {@link Version}
236+
*/
237+
public static Version getJavaVersion() {
238+
return Version.parse(System.getProperty("java.version"));
239+
}
240+
241+
/**
242+
* Fetch and return Elasticsearch version information
243+
* in raw string form.
244+
*
245+
* @return Elasticsearch version string
246+
*/
247+
public static String getElasticsearchVersionString() {
248+
InputStream in = ApiClient.class.getResourceAsStream(VERSION_PROPERTIES);
249+
if (in == null) {
250+
// Failed to locate version.properties file
251+
return null;
252+
}
253+
Properties properties = new Properties();
254+
try {
255+
properties.load(in);
256+
// This will return null if no version information is
257+
// found in the version.properties file
258+
return properties.getProperty("version");
259+
} catch (IOException e) {
260+
// Failed to read version.properties file
261+
return null;
262+
}
263+
}
264+
265+
/**
266+
* Fetch and return Elasticsearch version information
267+
* as a {@link Version} object.
268+
*
269+
* @return Elasticsearch {@link Version}
270+
*/
271+
public static Version getElasticsearchVersion() {
272+
String versionString = getElasticsearchVersionString();
273+
return versionString == null ? null : Version.parse(versionString);
274+
}
275+
276+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package co.elastic.clients.base;
21+
22+
/**
23+
* Interface implemented by any classes whose instances
24+
* can represent an HTTP header value, such as {@link UserAgent}.
25+
*/
26+
public interface ConvertibleToHeader {
27+
28+
/**
29+
* Convert this object into an HTTP header.
30+
*
31+
* @return {@link Header} instance
32+
*/
33+
Header toHeader();
34+
35+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package co.elastic.clients.base;
21+
22+
import co.elastic.clients.util.NamedValue;
23+
24+
/**
25+
* Raw HTTP header field, consisting of a string name and value.
26+
*/
27+
public class Header extends NamedValue<String> implements ConvertibleToHeader {
28+
29+
/**
30+
* Construct a raw header field.
31+
*
32+
* The {@link Object#toString()} method of the value passed is
33+
* used to obtain the field value sent over the wire.
34+
*
35+
* By convention, a null value denotes that the header with that
36+
* name is disabled, and will not be sent.
37+
*
38+
* @param name header field name
39+
* @param value header field value
40+
* @return new {@link Header} object
41+
*/
42+
public static Header raw(String name, Object value) {
43+
return new Header(name, value == null ? null : value.toString());
44+
}
45+
46+
private Header(String name, String value) {
47+
super(name, value);
48+
}
49+
50+
@Override
51+
public Header toHeader() {
52+
return this;
53+
}
54+
55+
}

0 commit comments

Comments
 (0)