Skip to content

Commit 5b3a874

Browse files
committed
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 49942c0 commit 5b3a874

File tree

3 files changed

+208
-14
lines changed

3 files changed

+208
-14
lines changed

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

+112-14
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,11 @@ protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEnt
12751275
return performRequest(request, requestConverter, (response) -> parseEntity(response.getEntity(), entityParser), ignores, headers);
12761276
}
12771277

1278+
/**
1279+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
1280+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
1281+
*/
1282+
@Deprecated
12781283
protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(Req request,
12791284
CheckedFunction<Req, Request, IOException> requestConverter,
12801285
RequestOptions options,
@@ -1284,6 +1289,18 @@ protected final <Req extends ActionRequest, Resp> Resp performRequestAndParseEnt
12841289
response -> parseEntity(response.getEntity(), entityParser), ignores);
12851290
}
12861291

1292+
/**
1293+
* Defines a helper method for performing a request and then parsing the returned entity using the provided entityParser.
1294+
*/
1295+
protected final <Req extends Validatable, Resp> Resp performRequestAndParseEntity(Req request,
1296+
CheckedFunction<Req, Request, IOException> requestConverter,
1297+
RequestOptions options,
1298+
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1299+
Set<Integer> ignores) throws IOException {
1300+
return performRequest(request, requestConverter, options,
1301+
response -> parseEntity(response.getEntity(), entityParser), ignores);
1302+
}
1303+
12871304
@Deprecated
12881305
protected final <Req extends ActionRequest, Resp> Resp performRequest(Req request,
12891306
CheckedFunction<Req, Request, IOException> requestConverter,
@@ -1292,15 +1309,46 @@ protected final <Req extends ActionRequest, Resp> Resp performRequest(Req reques
12921309
return performRequest(request, requestConverter, optionsForHeaders(headers), responseConverter, ignores);
12931310
}
12941311

1312+
/**
1313+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
1314+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
1315+
*/
1316+
@Deprecated
12951317
protected final <Req extends ActionRequest, Resp> Resp performRequest(Req request,
1296-
CheckedFunction<Req, Request, IOException> requestConverter,
1297-
RequestOptions options,
1298-
CheckedFunction<Response, Resp, IOException> responseConverter,
1299-
Set<Integer> ignores) throws IOException {
1318+
CheckedFunction<Req, Request, IOException> requestConverter,
1319+
RequestOptions options,
1320+
CheckedFunction<Response, Resp, IOException> responseConverter,
1321+
Set<Integer> ignores) throws IOException {
13001322
ActionRequestValidationException validationException = request.validate();
1301-
if (validationException != null) {
1323+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
13021324
throw validationException;
13031325
}
1326+
return internalPerformRequest(request, requestConverter, options, responseConverter, ignores);
1327+
}
1328+
1329+
/**
1330+
* Defines a helper method for performing a request.
1331+
*/
1332+
protected final <Req extends Validatable, Resp> Resp performRequest(Req request,
1333+
CheckedFunction<Req, Request, IOException> requestConverter,
1334+
RequestOptions options,
1335+
CheckedFunction<Response, Resp, IOException> responseConverter,
1336+
Set<Integer> ignores) throws IOException {
1337+
ValidationException validationException = request.validate();
1338+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
1339+
throw validationException;
1340+
}
1341+
return internalPerformRequest(request, requestConverter, options, responseConverter, ignores);
1342+
}
1343+
1344+
/**
1345+
* Provides common functionality for performing a request.
1346+
*/
1347+
private <Req, Resp> Resp internalPerformRequest(Req request,
1348+
CheckedFunction<Req, Request, IOException> requestConverter,
1349+
RequestOptions options,
1350+
CheckedFunction<Response, Resp, IOException> responseConverter,
1351+
Set<Integer> ignores) throws IOException {
13041352
Request req = requestConverter.apply(request);
13051353
req.setOptions(options);
13061354
Response response;
@@ -1337,15 +1385,32 @@ protected final <Req extends ActionRequest, Resp> void performRequestAsyncAndPar
13371385
listener, ignores, headers);
13381386
}
13391387

1388+
/**
1389+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
1390+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
1391+
*/
1392+
@Deprecated
13401393
protected final <Req extends ActionRequest, Resp> void performRequestAsyncAndParseEntity(Req request,
1341-
CheckedFunction<Req, Request, IOException> requestConverter,
1342-
RequestOptions options,
1343-
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1344-
ActionListener<Resp> listener, Set<Integer> ignores) {
1394+
CheckedFunction<Req, Request, IOException> requestConverter,
1395+
RequestOptions options,
1396+
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1397+
ActionListener<Resp> listener, Set<Integer> ignores) {
13451398
performRequestAsync(request, requestConverter, options,
13461399
response -> parseEntity(response.getEntity(), entityParser), listener, ignores);
13471400
}
13481401

1402+
/**
1403+
* Defines a helper method for asynchronously performing a request.
1404+
*/
1405+
protected final <Req extends Validatable, Resp> void performRequestAsyncAndParseEntity(Req request,
1406+
CheckedFunction<Req, Request, IOException> requestConverter,
1407+
RequestOptions options,
1408+
CheckedFunction<XContentParser, Resp, IOException> entityParser,
1409+
ActionListener<Resp> listener, Set<Integer> ignores) {
1410+
performRequestAsync(request, requestConverter, options,
1411+
response -> parseEntity(response.getEntity(), entityParser), listener, ignores);
1412+
}
1413+
13491414
@Deprecated
13501415
protected final <Req extends ActionRequest, Resp> void performRequestAsync(Req request,
13511416
CheckedFunction<Req, Request, IOException> requestConverter,
@@ -1354,16 +1419,48 @@ protected final <Req extends ActionRequest, Resp> void performRequestAsync(Req r
13541419
performRequestAsync(request, requestConverter, optionsForHeaders(headers), responseConverter, listener, ignores);
13551420
}
13561421

1422+
/**
1423+
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
1424+
* layer has been added to the ReST client, and requests should extend {@link Validatable} instead of {@link ActionRequest}.
1425+
*/
1426+
@Deprecated
13571427
protected final <Req extends ActionRequest, Resp> void performRequestAsync(Req request,
1358-
CheckedFunction<Req, Request, IOException> requestConverter,
1359-
RequestOptions options,
1360-
CheckedFunction<Response, Resp, IOException> responseConverter,
1361-
ActionListener<Resp> listener, Set<Integer> ignores) {
1428+
CheckedFunction<Req, Request, IOException> requestConverter,
1429+
RequestOptions options,
1430+
CheckedFunction<Response, Resp, IOException> responseConverter,
1431+
ActionListener<Resp> listener, Set<Integer> ignores) {
13621432
ActionRequestValidationException validationException = request.validate();
1363-
if (validationException != null) {
1433+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
13641434
listener.onFailure(validationException);
13651435
return;
13661436
}
1437+
internalPerformRequestAsync(request, requestConverter, options, responseConverter, listener, ignores);
1438+
}
1439+
1440+
/**
1441+
* Defines a helper method for asynchronously performing a request.
1442+
*/
1443+
protected final <Req extends Validatable, Resp> void performRequestAsync(Req request,
1444+
CheckedFunction<Req, Request, IOException> requestConverter,
1445+
RequestOptions options,
1446+
CheckedFunction<Response, Resp, IOException> responseConverter,
1447+
ActionListener<Resp> listener, Set<Integer> ignores) {
1448+
ValidationException validationException = request.validate();
1449+
if (validationException != null && validationException.validationErrors().isEmpty() == false) {
1450+
listener.onFailure(validationException);
1451+
return;
1452+
}
1453+
internalPerformRequestAsync(request, requestConverter, options, responseConverter, listener, ignores);
1454+
}
1455+
1456+
/**
1457+
* Provides common functionality for asynchronously performing a request.
1458+
*/
1459+
private <Req, Resp> void internalPerformRequestAsync(Req request,
1460+
CheckedFunction<Req, Request, IOException> requestConverter,
1461+
RequestOptions options,
1462+
CheckedFunction<Response, Resp, IOException> responseConverter,
1463+
ActionListener<Resp> listener, Set<Integer> ignores) {
13671464
Request req;
13681465
try {
13691466
req = requestConverter.apply(request);
@@ -1377,6 +1474,7 @@ protected final <Req extends ActionRequest, Resp> void performRequestAsync(Req r
13771474
client.performRequestAsync(req, responseListener);
13781475
}
13791476

1477+
13801478
final <Resp> ResponseListener wrapResponseListener(CheckedFunction<Response, Resp, IOException> responseConverter,
13811479
ActionListener<Resp> actionListener, Set<Integer> ignores) {
13821480
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)