How to hit ElasticSearch using Apache HttpClient - elasticsearch

I have SearchRequest object with all the Elasticsearch(ES) query data set. I cannot use RestHighLevel client for my usecase because it requires endpoint need to be passed at the time of instantiation. I gets ES endpoint dynamically based on some condition. One way is to always create new RestHighLevel client which will be inefficient approach. Other way is to create static CloseableHttpClient on service start and make HttpPost request with dynamic endpoint. I wanted to take later approach but don't know how to convert SearchRequest object into json query string.
Any code reference/snippet would be very helpful
private final CloseableHttpClient client;
public GenericElasticSearchResponse search(#Nonnull final SearchRequest searchRequest,
#Nonnull final RoutingConfig route) {
final URIBuilder builder = new URIBuilder()
.setScheme(route.getScheme())
.setHost(route.getESEndpoint())
.setPort(Optional.ofNullable(route.getPort())
.orElse(80))
.setPath("/sessions*/_search");
final URI uri = builder.build();
final ContentType contentType = ContentType.create("application/json", "UTF-8");
final HttpPost httpPost = new HttpPost(uri);
httpPost.setEntity(entity);
final CloseableHttpResponse response = client.execute(httpPost);
final String responseEntity;
try (final Reader reader = new InputStreamReader(response.getEntity().getContent(), Charsets.UTF_8)) {
responseEntity = CharStreams.toString(reader);
}
final SearchResponse searchResponse = objectMapper.readValue(responseEntity, SearchResponse.class);
return new ElasticSearchResponse(searchResponse);
}

I found searchRequest.source().toString() was actually returning json form of SearchRequest. Following is complete code snippet for hitting ES via Apache client
final EndpointConfig endpoint = route.getEndpoint();
final URIBuilder builder = new URIBuilder()
.setScheme(endpoint.getScheme())
.setHost(endpoint.getHost())
.setPort(Optional.ofNullable(endpoint.getPort())
.orElse(HTTPS_PORT))
.setPath(Optional.ofNullable(endpoint.getQueryPath())
.orElse(StringUtils.EMPTY));
final URI uri = builder.build();
final ContentType contentType = ContentType.create("application/json", "UTF-8");
final String queryString = searchRequest.source().toString();
final StringEntity entity = new StringEntity(queryString, contentType);
final HttpPost httpPost = new HttpPost(uri);
httpPost.setEntity(entity);
final CloseableHttpResponse response = sendRequest(httpPost);
final String responseEntity;
try (final Reader reader = new InputStreamReader(response.getEntity().getContent(), Charsets.UTF_8)) {
responseEntity = CharStreams.toString(reader);
}
log.info("ElasticSearchClient response: Code: {}, Entity {}", response.getCode(), responseEntity);
SearchResponse searchResponse = null;
if (Objects.nonNull(responseEntity)) {
searchResponse = parseResponse(responseEntity, searchRequest, response.getCode());
log.info("ElasticSearchClient searchResponse- {} ", searchResponse);
}
return new ElasticSearchResponse(searchResponse);
} catch (final URISyntaxException e) {
throw new IllegalStateException(
String.format("Invalid URI. host: %s", route.getEndpoint()), e);
} catch (final IOException e) {
throw new IllegalStateException("ElasticSearch Request failed.", e);
}
private SearchResponse parseResponse(#Nonnull final String responseEntity,
#Nonnull final SearchRequest searchRequest,
final int responseCode) {
if (responseCode >= 400 || responseCode < 200) {
log.info("ES error response - {} ", responseEntity);
final ESErrorResponse response = GSON.fromJson(responseEntity, ESErrorResponse.class);
throw new IllegalStateException();
}
SearchResponse searchResponse = null;
final NamedXContentRegistry registry = new NamedXContentRegistry(getDefaultNamedXContents());
final XContentParser parser;
try {
parser = JsonXContent.jsonXContent.createParser(registry,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, responseEntity);
searchResponse = SearchResponse.fromXContent(parser);
} catch (IOException e) {
throw new IllegalStateException("Error while parsing response ", e);
}
return searchResponse;
}
public static List<NamedXContentRegistry.Entry> getDefaultNamedXContents() {
final Map<String, ContextParser<Object, ? extends Aggregation>> map = new HashMap<>();
map.put(TopHitsAggregationBuilder.NAME, (p, c) -> ParsedTopHits.fromXContent(p, (String) c));
map.put(StringTerms.NAME, (p, c) -> ParsedStringTerms.fromXContent(p, (String) c));
return map.entrySet().stream()
.map(entry -> new NamedXContentRegistry.Entry(Aggregation.class, new ParseField(entry.getKey()), entry.getValue()))
.collect(Collectors.toList());
}
private CloseableHttpResponse sendRequest(final HttpPost httpPost) throws IOException {
return client.execute(httpPost);
}

Related

How to Redirect request as post using ResponseEntity

I trying to include response from other url from ResponseEntity for oauth authorization but it is failing as I am unable to specify request method.
Below is the code
#RequestMapping(value = "/login/otp", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE})
#ResponseBody
public ResponseEntity<?> getOTP(#Valid #RequestBody String loginDtls,UriComponentsBuilder ucBuilder) {
LoginDAO login = null;
ResponseEntity<?> resp = null;
try {
ObjectMapper mapper = new ObjectMapper();
String userId = "";
try {
JsonNode root = mapper.readTree(loginDtls);
userId = root.get("userId").textValue();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("UserController : getting otp for contact "+ userId);
login = loginService.findByUserId(userId);
if (login==null) {
System.out.println("A UserDAO with name " + userId + " does not exist");
resp = new ResponseEntity<String>(HttpStatus.NOT_FOUND);
}
String otp = GenUtil.generateOTP();
LoginDAO loginUpd = new LoginDAO(login);
loginUpd.setOtp(otp);
loginUpd.setOtpTimestamp(new Timestamp(System.currentTimeMillis()));
loginService.updateLogin(loginUpd);
System.out.println(loginUpd);
resp = getAuthenticated(ucBuilder);
System.out.println(resp.getStatusCodeValue());
System.out.println(resp.getBody());
}catch(Exception e) {
e.printStackTrace();
}
resp = new ResponseEntity<String>(login.toString(), HttpStatus.OK);
return resp;
}
private ResponseEntity<?> getAuthenticated(UriComponentsBuilder ucBuilder){
HttpHeaders headers = new HttpHeaders();
URI uri= ucBuilder.path("/oauth/token"+PASSWORD_GRANT).build().toUri();
List<MediaType> accept = new ArrayList<MediaType>();
accept.add(MediaType.APPLICATION_JSON_UTF8);
headers.setAccept(accept);
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
headers.setBasicAuth("my-trusted-client", "secret");
System.out.println(headers);
ResponseEntity<?> resp = ResponseEntity.created(uri).headers(headers).build();
return resp;
}

SPRING CLOUD: RestTemplate postForObject cannot send request body

This is my consumer request function:
#PostMapping(value = "/spuSkuInfo")
public DataResponseDto<Map<String, Object>> addSpuAndSkuInfo(#Valid SpuSkuInfoBo spuSkuInfoBo) {
String url = REST_URL_PREFIX + "addSpuAndSkuInfo";
DataResponseDto<Map<String, Object>> dataResponseDto;
MultiValueMap<String,SpuSkuInfoBo> reqMap = new LinkedMultiValueMap<>();
reqMap.add("spuSkuInfoBo",spuSkuInfoBo);
HttpEntity<MultiValueMap<String,SpuSkuInfoBo>> httpEntity = new HttpEntity<>(reqMap);
dataResponseDto = restTemplate.postForObject(url,httpEntity,DataResponseDto.class);
}
This is my provider:
#PostMapping(value = "/addSpuAndSkuInfo")
public DataResponseDto<Map<String, Object>> addSpuAndSkuInfo(SpuSkuInfoBo spuSkuInfoBo) {
DataResponseDto<Map<String, Object>> responseDto;
try {
responseDto = spuSkuService.addSpuAndSkuInfo(spuSkuInfoBo);
} catch (Exception e) {
logger.error("addSpuAndSkuInfo", e);
responseDto = new DataResponseDto<>();
responseDto.setRspCd(PrdErrorCode.PRD_FAIL_CD);
responseDto.setRspInf("");
return responseDto;
}
return responseDto;
}
In consumer I can got the Pojo 'SpuSkuInfoBo'
And When I debugger in provider, I just can not receive the request body 'SpuSkuInfoBo'
Finally I solved the problem by adding #RequstBody in provider function
public DataResponseDto<Map<String, Object>> addSpuAndSkuInfo(#RequestBody SpuSkuInfoBo spuSkuInfoBo)

elasticsearch-rest-high-level-client:6.5.0 BulkRequest Not working anymore

I've updated elasticsearch from 6.4.2 to 6.5.0 and the BulkRequest using the rest high level client api is not working anymore:
final BulkRequest request = new BulkRequest();
myarray().forEach(elem -> {
try {
final XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
builder.timeField("#timestamp", elem.getTimestamp());
builder.field("metric", elem.getMetric().getName());
builder.field("resource", elem.getResource().getName());
builder.field("value", elem.getValue());
builder.field("windowId", elem.getWindowId());
}
builder.endObject();
System.out.println(builder.prettyPrint());
final IndexRequest indexRequest = new IndexRequest("myindex-2018.11.20", "mytype");
indexRequest.source(builder);
request.add(indexRequest);
} catch (IOException e) {
logger.log(Level.SEVERE, "Error forward", e);
}
});
BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
If I perform a single IndexRequest it works fine:
final XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
builder.timeField("#timestamp", System.currentTimeMillis());
builder.field("metric", "test");
builder.field("resource", "test");
builder.field("value", "-1");
builder.field("windowId", "test");
}
builder.endObject();
final IndexRequest indexRequest = new IndexRequest("myindex-2018.11.20", "mytype");
indexRequest.source(builder);
final IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
Both queries where running well with the version 6.4.2, now with the version 6.5.0 only the second one is working.
I don't receive any errors

How to convert collection to csv with jackson in java spring?

I have a problem to convert a java.util.Collection to a csv file with jackson.
In the following code you can see a method to convert the collection to a csv-string.
But i need a method to convert the collection with com.fasterxml.jackson.
The Enum "DownloadType" get the column and headerlines for csv file.
Do you have an idea to fix them?
#RequestMapping(value = "/csv",
produces = {"text/csv"},
consumes = {"application/json"},
method = RequestMethod.POST)
public ResponseEntity<Object> exportCsv()
{
ResponseEntity<Object> response = null;
try
{
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8");
headers.add(HttpHeaders.CACHE_CONTROL, "no-store, must-revalidate");
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=\"export.csv\"");
headers.add(HttpHeaders.EXPIRES, "0");
byte[] csvBytes = null;
byte[] headerBytes = null;
byte[] lineBytes = null;
CsvMapper mapper = new
Collection<User> users = getUsers()
headerBytes = DownloadType.USER.getHeaderLine().getBytes("UTF-8");
lineBytes = mapper.writer(DownloadType.USER.getCsvSchema()).writeValueAsBytes(users);
if (headerBytes != null && lineBytes != null)
{
csvBytes = new byte[headerBytes.length + lineBytes.length];
System.arraycopy(headerBytes, 0, csvBytes, 0, headerBytes.length);
System.arraycopy(lineBytes, 0, csvBytes, headerBytes.length, lineBytes.length);
}
response = new ResponseEntity<>(csvBytes, headers, HttpStatus.OK);
}
catch (Exception e)
{
LOG.error(e.getMessage(), e);
}
return response;
}
Maybe try something like this. By writing the data directly to the servlet response the string will get returned directly back to the client as is without formatting or post-processing.
#RequestMapping(value = "/csv",
produces = {"text/csv"},
consumes = {"application/json"},
method = RequestMethod.POST)
public void exportCsv(HttpServletResponse response)
{
...
String headerString = DownloadType.USER.getHeaderLine()
String data = mapper.writer(DownloadType.USER.getCsvSchema()).writeValueAsString(users);
response.setContentType("text/plain; charset=utf-8");
response.getWriter().print(headerString);
response.getWriter().print(data);
Adapted from:
How to Return CSV Data in Browser From Spring Controller

Calling a different host from Spring Controller

My localhost is : http://localhost:8585/api/getproducts where i use #Requestmapping(/api/getproducts) in my ProductController to get to my product page.
On click of a button, i need to call an api on a different host :
http://10.120.130.22:9292/ and i tried to use the below code in a new Controller to call the host:
#RequestMapping("Trainer/reStaff/")
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody response(#RequestParam("trainingId") final int trainingId, HttpServletRequest request)
throws ClientProtocolException, IOException {
String hostname="http://10.120.130.22:9292/";
CloseableHttpClient httpclient = HttpClients.custom().build();
CloseableHttpResponse response=null;
try{
String uri=hostname+"Trainer/reStaff/?trainingId="+trainingId;
HttpPost httpPost = new HttpPost(uri);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-Type", "application/json");
response = httpclient.execute(httpPost);
String responseData = EntityUtils.toString(response.getEntity());
if(response.getStatusLine().getStatusCode()==200)
System.out.println(responseData+"\n");
else
System.out.println("Error :" + responseData+"\n");
}finally {
httpclient.close();
response.close();
}
But i get the error : HTTP Status 404 - type Status reportmessage description The requested resource is not available.
How do i call the new host from my controller?
I understood how this works. We need to pass the url through httpPost in the service layer :
HttpPost httpPost = new HttpPost(hostUri);
JsonObject jsonResponse = null;
try {
String httpRequestBody = jsonRequestBuilder.build().toString();
logger.info("Request Body: " + httpRequestBody);
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connManager).build();
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("Accept", "application/json");
httpPost.setEntity(new StringEntity(httpRequestBody));
HttpResponse httpResponse = httpClient.execute(httpPost);
logger.debug("Response Status: " + httpResponse.getStatusLine().getStatusCode());
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
String line;
StringBuffer httpResponseBody = new StringBuffer();
while ((line = reader.readLine()) != null) {
httpResponseBody.append(line);
}
logger.info("Response Body: " + httpResponseBody.toString());
JsonReader jsonReader = Json.createReader(new StringReader(httpResponseBody.toString()));
jsonResponse = jsonReader.readObject();
jsonReader.close();
} catch (Exception ex) {
logger.error("Error occurred while invoking POST on ep: " + hostUrl, ex);
} finally {
httpPost.releaseConnection();
}
logger.debug("Exiting");
return jsonResponse;

Resources