Skip to content

Commit 89e606e

Browse files
committed
Make RestHighLevelClient's Request class public (#26627)
Request class is currently package protected, making it difficult for the users to extend the RestHighLevelClient and to use its protected methods to execute requests. This commit makes the Request class public and changes few methods of RestHighLevelClient to be protected.
1 parent 872004a commit 89e606e

File tree

5 files changed

+171
-93
lines changed

5 files changed

+171
-93
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,30 +63,47 @@
6363
import java.util.HashMap;
6464
import java.util.Locale;
6565
import java.util.Map;
66+
import java.util.Objects;
6667
import java.util.StringJoiner;
6768

68-
final class Request {
69+
public final class Request {
6970

7071
static final XContentType REQUEST_BODY_CONTENT_TYPE = XContentType.JSON;
7172

72-
final String method;
73-
final String endpoint;
74-
final Map<String, String> params;
75-
final HttpEntity entity;
73+
private final String method;
74+
private final String endpoint;
75+
private final Map<String, String> parameters;
76+
private final HttpEntity entity;
7677

77-
Request(String method, String endpoint, Map<String, String> params, HttpEntity entity) {
78-
this.method = method;
79-
this.endpoint = endpoint;
80-
this.params = params;
78+
public Request(String method, String endpoint, Map<String, String> parameters, HttpEntity entity) {
79+
this.method = Objects.requireNonNull(method, "method cannot be null");
80+
this.endpoint = Objects.requireNonNull(endpoint, "endpoint cannot be null");
81+
this.parameters = Objects.requireNonNull(parameters, "parameters cannot be null");
8182
this.entity = entity;
8283
}
8384

85+
public String getMethod() {
86+
return method;
87+
}
88+
89+
public String getEndpoint() {
90+
return endpoint;
91+
}
92+
93+
public Map<String, String> getParameters() {
94+
return parameters;
95+
}
96+
97+
public HttpEntity getEntity() {
98+
return entity;
99+
}
100+
84101
@Override
85102
public String toString() {
86103
return "Request{" +
87104
"method='" + method + '\'' +
88105
", endpoint='" + endpoint + '\'' +
89-
", params=" + params +
106+
", params=" + parameters +
90107
", hasBody=" + (entity != null) +
91108
'}';
92109
}
@@ -233,7 +250,7 @@ static Request bulk(BulkRequest bulkRequest) throws IOException {
233250

234251
static Request exists(GetRequest getRequest) {
235252
Request request = get(getRequest);
236-
return new Request(HttpHead.METHOD_NAME, request.endpoint, request.params, null);
253+
return new Request(HttpHead.METHOD_NAME, request.endpoint, request.parameters, null);
237254
}
238255

239256
static Request get(GetRequest getRequest) {
@@ -381,7 +398,7 @@ static String endpoint(String... parts) {
381398
* @return the {@link ContentType}
382399
*/
383400
@SuppressForbidden(reason = "Only allowed place to convert a XContentType to a ContentType")
384-
static ContentType createContentType(final XContentType xContentType) {
401+
public static ContentType createContentType(final XContentType xContentType) {
385402
return ContentType.create(xContentType.mediaTypeWithoutParameters(), (Charset) null);
386403
}
387404

client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ protected <Req extends ActionRequest, Resp> Resp performRequest(Req request,
425425
Request req = requestConverter.apply(request);
426426
Response response;
427427
try {
428-
response = client.performRequest(req.method, req.endpoint, req.params, req.entity, headers);
428+
response = client.performRequest(req.getMethod(), req.getEndpoint(), req.getParameters(), req.getEntity(), headers);
429429
} catch (ResponseException e) {
430430
if (ignores.contains(e.getResponse().getStatusLine().getStatusCode())) {
431431
try {
@@ -474,7 +474,7 @@ protected <Req extends ActionRequest, Resp> void performRequestAsync(Req request
474474
}
475475

476476
ResponseListener responseListener = wrapResponseListener(responseConverter, listener, ignores);
477-
client.performRequestAsync(req.method, req.endpoint, req.params, req.entity, responseListener, headers);
477+
client.performRequestAsync(req.getMethod(), req.getEndpoint(), req.getParameters(), req.getEntity(), responseListener, headers);
478478
}
479479

480480
<Resp> ResponseListener wrapResponseListener(CheckedFunction<Response, Resp, IOException> responseConverter,
@@ -522,7 +522,7 @@ public void onFailure(Exception exception) {
522522
* that wraps the original {@link ResponseException}. The potential exception obtained while parsing is added to the returned
523523
* exception as a suppressed exception. This method is guaranteed to not throw any exception eventually thrown while parsing.
524524
*/
525-
ElasticsearchStatusException parseResponseException(ResponseException responseException) {
525+
protected ElasticsearchStatusException parseResponseException(ResponseException responseException) {
526526
Response response = responseException.getResponse();
527527
HttpEntity entity = response.getEntity();
528528
ElasticsearchStatusException elasticsearchException;
@@ -542,8 +542,8 @@ ElasticsearchStatusException parseResponseException(ResponseException responseEx
542542
return elasticsearchException;
543543
}
544544

545-
<Resp> Resp parseEntity(
546-
HttpEntity entity, CheckedFunction<XContentParser, Resp, IOException> entityParser) throws IOException {
545+
protected <Resp> Resp parseEntity(final HttpEntity entity,
546+
final CheckedFunction<XContentParser, Resp, IOException> entityParser) throws IOException {
547547
if (entity == null) {
548548
throw new IllegalStateException("Response body expected but not returned");
549549
}

client/rest-high-level/src/test/java/org/elasticsearch/client/CustomRestHighLevelClientTests.java

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,29 @@
1919

2020
package org.elasticsearch.client;
2121

22-
import org.apache.lucene.util.BytesRef;
23-
import org.elasticsearch.Build;
24-
import org.elasticsearch.Version;
25-
import org.elasticsearch.action.ActionListener;
26-
import org.elasticsearch.action.main.MainRequest;
27-
import org.elasticsearch.action.main.MainResponse;
2822
import org.apache.http.Header;
2923
import org.apache.http.HttpEntity;
3024
import org.apache.http.HttpHost;
31-
import org.apache.http.HttpResponse;
3225
import org.apache.http.ProtocolVersion;
3326
import org.apache.http.RequestLine;
3427
import org.apache.http.client.methods.HttpGet;
3528
import org.apache.http.entity.ByteArrayEntity;
3629
import org.apache.http.entity.ContentType;
3730
import org.apache.http.message.BasicHeader;
38-
import org.apache.http.message.BasicHttpResponse;
3931
import org.apache.http.message.BasicRequestLine;
4032
import org.apache.http.message.BasicStatusLine;
33+
import org.apache.lucene.util.BytesRef;
34+
import org.elasticsearch.Build;
35+
import org.elasticsearch.Version;
36+
import org.elasticsearch.action.ActionListener;
37+
import org.elasticsearch.action.main.MainRequest;
38+
import org.elasticsearch.action.main.MainResponse;
39+
import org.elasticsearch.action.support.PlainActionFuture;
40+
import org.elasticsearch.client.Request;
41+
import org.elasticsearch.client.Response;
42+
import org.elasticsearch.client.ResponseListener;
43+
import org.elasticsearch.client.RestClient;
44+
import org.elasticsearch.client.RestHighLevelClient;
4145
import org.elasticsearch.cluster.ClusterName;
4246
import org.elasticsearch.common.SuppressForbidden;
4347
import org.elasticsearch.common.xcontent.XContentHelper;
@@ -48,18 +52,22 @@
4852
import java.io.IOException;
4953
import java.lang.reflect.Method;
5054
import java.lang.reflect.Modifier;
55+
import java.util.Arrays;
5156
import java.util.Collections;
57+
import java.util.List;
58+
import java.util.stream.Collectors;
5259

5360
import static java.util.Collections.emptyMap;
5461
import static java.util.Collections.emptySet;
55-
import static org.elasticsearch.client.ESRestHighLevelClientTestCase.execute;
62+
import static org.hamcrest.Matchers.containsInAnyOrder;
5663
import static org.mockito.Matchers.any;
5764
import static org.mockito.Matchers.anyMapOf;
5865
import static org.mockito.Matchers.anyObject;
5966
import static org.mockito.Matchers.anyVararg;
6067
import static org.mockito.Matchers.eq;
6168
import static org.mockito.Mockito.doAnswer;
6269
import static org.mockito.Mockito.mock;
70+
import static org.mockito.Mockito.when;
6371

6472
/**
6573
* Test and demonstrates how {@link RestHighLevelClient} can be extended to support custom endpoints.
@@ -92,31 +100,45 @@ public void testCustomEndpoint() throws IOException {
92100
final MainRequest request = new MainRequest();
93101
final Header header = new BasicHeader("node_name", randomAlphaOfLengthBetween(1, 10));
94102

95-
MainResponse response = execute(request, restHighLevelClient::custom, restHighLevelClient::customAsync, header);
103+
MainResponse response = restHighLevelClient.custom(request, header);
96104
assertEquals(header.getValue(), response.getNodeName());
97105

98-
response = execute(request, restHighLevelClient::customAndParse, restHighLevelClient::customAndParseAsync, header);
106+
response = restHighLevelClient.customAndParse(request, header);
99107
assertEquals(header.getValue(), response.getNodeName());
100108
}
101109

110+
public void testCustomEndpointAsync() throws Exception {
111+
final MainRequest request = new MainRequest();
112+
final Header header = new BasicHeader("node_name", randomAlphaOfLengthBetween(1, 10));
113+
114+
PlainActionFuture<MainResponse> future = PlainActionFuture.newFuture();
115+
restHighLevelClient.customAsync(request, future, header);
116+
assertEquals(header.getValue(), future.get().getNodeName());
117+
118+
future = PlainActionFuture.newFuture();
119+
restHighLevelClient.customAndParseAsync(request, future, header);
120+
assertEquals(header.getValue(), future.get().getNodeName());
121+
}
122+
102123
/**
103124
* The {@link RestHighLevelClient} must declare the following execution methods using the <code>protected</code> modifier
104125
* so that they can be used by subclasses to implement custom logic.
105126
*/
106127
@SuppressForbidden(reason = "We're forced to uses Class#getDeclaredMethods() here because this test checks protected methods")
107128
public void testMethodsVisibility() throws ClassNotFoundException {
108-
String[] methodNames = new String[]{"performRequest", "performRequestAndParseEntity", "performRequestAsync",
109-
"performRequestAsyncAndParseEntity"};
110-
for (String methodName : methodNames) {
111-
boolean found = false;
112-
for (Method method : RestHighLevelClient.class.getDeclaredMethods()) {
113-
if (method.getName().equals(methodName)) {
114-
assertTrue("Method " + methodName + " must be protected", Modifier.isProtected(method.getModifiers()));
115-
found = true;
116-
}
117-
}
118-
assertTrue("Failed to find method " + methodName, found);
119-
}
129+
final String[] methodNames = new String[]{"performRequest",
130+
"performRequestAsync",
131+
"performRequestAndParseEntity",
132+
"performRequestAsyncAndParseEntity",
133+
"parseEntity",
134+
"parseResponseException"};
135+
136+
final List<String> protectedMethods = Arrays.stream(RestHighLevelClient.class.getDeclaredMethods())
137+
.filter(method -> Modifier.isProtected(method.getModifiers()))
138+
.map(Method::getName)
139+
.collect(Collectors.toList());
140+
141+
assertThat(protectedMethods, containsInAnyOrder(methodNames));
120142
}
121143

122144
/**
@@ -135,15 +157,20 @@ private Void mockPerformRequestAsync(Header httpHeader, ResponseListener respons
135157
* Mocks the synchronous request execution like if it was executed by Elasticsearch.
136158
*/
137159
private Response mockPerformRequest(Header httpHeader) throws IOException {
160+
final Response mockResponse = mock(Response.class);
161+
when(mockResponse.getHost()).thenReturn(new HttpHost("localhost", 9200));
162+
138163
ProtocolVersion protocol = new ProtocolVersion("HTTP", 1, 1);
139-
HttpResponse httpResponse = new BasicHttpResponse(new BasicStatusLine(protocol, 200, "OK"));
164+
when(mockResponse.getStatusLine()).thenReturn(new BasicStatusLine(protocol, 200, "OK"));
140165

141166
MainResponse response = new MainResponse(httpHeader.getValue(), Version.CURRENT, ClusterName.DEFAULT, "_na", Build.CURRENT, true);
142167
BytesRef bytesRef = XContentHelper.toXContent(response, XContentType.JSON, false).toBytesRef();
143-
httpResponse.setEntity(new ByteArrayEntity(bytesRef.bytes, ContentType.APPLICATION_JSON));
168+
when(mockResponse.getEntity()).thenReturn(new ByteArrayEntity(bytesRef.bytes, ContentType.APPLICATION_JSON));
144169

145170
RequestLine requestLine = new BasicRequestLine(HttpGet.METHOD_NAME, ENDPOINT, protocol);
146-
return new Response(requestLine, new HttpHost("localhost", 9200), httpResponse);
171+
when(mockResponse.getRequestLine()).thenReturn(requestLine);
172+
173+
return mockResponse;
147174
}
148175

149176
/**

0 commit comments

Comments
 (0)