Skip to content

Commit e991208

Browse files
authored
HLRC: Create server agnostic request and response (#32912)
The HLRC has historically reused the same Request and Response classes that the server module uses. This commit deprecates the use of any server module Request and Response classes, and adds a small bit of validation logic that differs from server slightly, in that it does not assume a check for a null ValidationException class is not enough to determine if validation failed.
1 parent 67bfb76 commit e991208

File tree

3 files changed

+209
-14
lines changed

3 files changed

+209
-14
lines changed

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

+113-14
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,11 @@ public final void fieldCapsAsync(FieldCapabilitiesRequest fieldCapabilitiesReque
960960
FieldCapabilitiesResponse::fromXContent, listener, emptySet());
961961
}
962962

963+
/**
964+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
965+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
966+
*/
967+
@Deprecated
963968
protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(Req request,
964969
CheckedFunction<Req, Request, IOException> requestConverter,
965970
RequestOptions options,
@@ -969,15 +974,58 @@ protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEnt
969974
response -> parseEntity(response.getEntity(), entityParser), ignores);
970975
}
971976

977+
/**
978+
* Defines a helper method for performing a request and then parsing the returned entity using the provided entityParser.
979+
*/
980+
protected final <Req extends Validatable, Resp> Resp performRequestAndParseEntity(Req request,
981+
CheckedFunction<Req, Request, IOException> requestConverter,
982+
RequestOptions options,
983+
CheckedFunction<XContentParser, Resp, IOException> entityParser,
984+
Set<Integer> ignores) throws IOException {
985+
return performRequest(request, requestConverter, options,
986+
response -> parseEntity(response.getEntity(), entityParser), ignores);
987+
}
988+
989+
/**
990+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
991+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
992+
*/
993+
@Deprecated
972994
protected final <Req extends ActionRequest, Resp> Resp performRequest(Req request,
973-
CheckedFunction<Req, Request, IOException> requestConverter,
974-
RequestOptions options,
975-
CheckedFunction<Response, Resp, IOException> responseConverter,
976-
Set<Integer> ignores) throws IOException {
995+
CheckedFunction<Req, Request, IOException> requestConverter,
996+
RequestOptions options,
997+
CheckedFunction<Response, Resp, IOException> responseConverter,
998+
Set<Integer> ignores) throws IOException {
977999
ActionRequestValidationException validationException = request.validate();
978-
if (validationException != null) {
1000+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
9791001
throw validationException;
9801002
}
1003+
return internalPerformRequest(request, requestConverter, options, responseConverter, ignores);
1004+
}
1005+
1006+
/**
1007+
* Defines a helper method for performing a request.
1008+
*/
1009+
protected final <Req extends Validatable, Resp> Resp performRequest(Req request,
1010+
CheckedFunction<Req, Request, IOException> requestConverter,
1011+
RequestOptions options,
1012+
CheckedFunction<Response, Resp, IOException> responseConverter,
1013+
Set<Integer> ignores) throws IOException {
1014+
ValidationException validationException = request.validate();
1015+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
1016+
throw validationException;
1017+
}
1018+
return internalPerformRequest(request, requestConverter, options, responseConverter, ignores);
1019+
}
1020+
1021+
/**
1022+
* Provides common functionality for performing a request.
1023+
*/
1024+
private <Req, Resp> Resp internalPerformRequest(Req request,
1025+
CheckedFunction<Req, Request, IOException> requestConverter,
1026+
RequestOptions options,
1027+
CheckedFunction<Response, Resp, IOException> responseConverter,
1028+
Set<Integer> ignores) throws IOException {
9811029
Request req = requestConverter.apply(request);
9821030
req.setOptions(options);
9831031
Response response;
@@ -1005,25 +1053,75 @@ protected final <Req extends ActionRequest, Resp> Resp performRequest(Req reques
10051053
}
10061054
}
10071055

1056+
/**
1057+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
1058+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
1059+
*/
1060+
@Deprecated
10081061
protected final <Req extends ActionRequest, Resp> void performRequestAsyncAndParseEntity(Req request,
1009-
CheckedFunction<Req, Request, IOException> requestConverter,
1010-
RequestOptions options,
1011-
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1012-
ActionListener<Resp> listener, Set<Integer> ignores) {
1062+
CheckedFunction<Req, Request, IOException> requestConverter,
1063+
RequestOptions options,
1064+
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1065+
ActionListener<Resp> listener, Set<Integer> ignores) {
10131066
performRequestAsync(request, requestConverter, options,
10141067
response -> parseEntity(response.getEntity(), entityParser), listener, ignores);
10151068
}
10161069

1070+
/**
1071+
* Defines a helper method for asynchronously performing a request.
1072+
*/
1073+
protected final <Req extends Validatable, Resp> void performRequestAsyncAndParseEntity(Req request,
1074+
CheckedFunction<Req, Request, IOException> requestConverter,
1075+
RequestOptions options,
1076+
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1077+
ActionListener<Resp> listener, Set<Integer> ignores) {
1078+
performRequestAsync(request, requestConverter, options,
1079+
response -> parseEntity(response.getEntity(), entityParser), listener, ignores);
1080+
}
1081+
1082+
1083+
/**
1084+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
1085+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
1086+
*/
1087+
@Deprecated
10171088
protected final <Req extends ActionRequest, Resp> void performRequestAsync(Req request,
1018-
CheckedFunction<Req, Request, IOException> requestConverter,
1019-
RequestOptions options,
1020-
CheckedFunction<Response, Resp, IOException> responseConverter,
1021-
ActionListener<Resp> listener, Set<Integer> ignores) {
1089+
CheckedFunction<Req, Request, IOException> requestConverter,
1090+
RequestOptions options,
1091+
CheckedFunction<Response, Resp, IOException> responseConverter,
1092+
ActionListener<Resp> listener, Set<Integer> ignores) {
10221093
ActionRequestValidationException validationException = request.validate();
1023-
if (validationException != null) {
1094+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
10241095
listener.onFailure(validationException);
10251096
return;
10261097
}
1098+
internalPerformRequestAsync(request, requestConverter, options, responseConverter, listener, ignores);
1099+
}
1100+
1101+
/**
1102+
* Defines a helper method for asynchronously performing a request.
1103+
*/
1104+
protected final <Req extends Validatable, Resp> void performRequestAsync(Req request,
1105+
CheckedFunction<Req, Request, IOException> requestConverter,
1106+
RequestOptions options,
1107+
CheckedFunction<Response, Resp, IOException> responseConverter,
1108+
ActionListener<Resp> listener, Set<Integer> ignores) {
1109+
ValidationException validationException = request.validate();
1110+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
1111+
listener.onFailure(validationException);
1112+
return;
1113+
}
1114+
internalPerformRequestAsync(request, requestConverter, options, responseConverter, listener, ignores);
1115+
}
1116+
1117+
/**
1118+
* Provides common functionality for asynchronously performing a request.
1119+
*/
1120+
private <Req, Resp> void internalPerformRequestAsync(Req request,
1121+
CheckedFunction<Req, Request, IOException> requestConverter,
1122+
RequestOptions options,
1123+
CheckedFunction<Response, Resp, IOException> responseConverter,
1124+
ActionListener<Resp> listener, Set<Integer> ignores) {
10271125
Request req;
10281126
try {
10291127
req = requestConverter.apply(request);
@@ -1037,6 +1135,7 @@ protected final <Req extends ActionRequest, Resp> void performRequestAsync(Req r
10371135
client.performRequestAsync(req, responseListener);
10381136
}
10391137

1138+
10401139
final <Resp> ResponseListener wrapResponseListener(CheckedFunction<Response, Resp, IOException> responseConverter,
10411140
ActionListener<Resp> actionListener, Set<Integer> ignores) {
10421141
return new ResponseListener() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to Elasticsearch 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 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+
package org.elasticsearch.client;
20+
21+
/**
22+
* Defines a validation layer for Requests.
23+
*/
24+
public interface Validatable {
25+
ValidationException EMPTY_VALIDATION = new ValidationException() {
26+
@Override
27+
public void addValidationError(String error) {
28+
throw new UnsupportedOperationException("Validation messages should not be added to the empty validation");
29+
}
30+
};
31+
32+
/**
33+
* Perform validation. This method does not have to be overridden in the event that no validation needs to be done.
34+
*
35+
* @return potentially null, in the event of older actions, an empty {@link ValidationException} in newer actions, or finally a
36+
* {@link ValidationException} that contains a list of all failed validation.
37+
*/
38+
default ValidationException validate() {
39+
return EMPTY_VALIDATION;
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Licensed to Elasticsearch 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 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+
package org.elasticsearch.client;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
/**
25+
* Encapsulates an accumulation of validation errors
26+
*/
27+
public class ValidationException extends IllegalArgumentException {
28+
private final List<String> validationErrors = new ArrayList<>();
29+
30+
/**
31+
* Add a new validation error to the accumulating validation errors
32+
* @param error the error to add
33+
*/
34+
public void addValidationError(String error) {
35+
validationErrors.add(error);
36+
}
37+
38+
/**
39+
* Returns the validation errors accumulated
40+
*/
41+
public final List<String> validationErrors() {
42+
return validationErrors;
43+
}
44+
45+
@Override
46+
public final String getMessage() {
47+
StringBuilder sb = new StringBuilder();
48+
sb.append("Validation Failed: ");
49+
int index = 0;
50+
for (String error : validationErrors) {
51+
sb.append(++index).append(": ").append(error).append(";");
52+
}
53+
return sb.toString();
54+
}
55+
}

0 commit comments

Comments
 (0)