All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.cafdataprocessing.elastic.tools.ElasticRequestHandler Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020-2024 Open Text.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.cafdataprocessing.elastic.tools;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.util.EntityUtils;
import org.opensearch.client.Request;
import org.opensearch.client.Response;
import org.opensearch.client.ResponseException;
import org.opensearch.client.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.cafdataprocessing.elastic.tools.exceptions.GetIndexException;
import com.github.cafdataprocessing.elastic.tools.exceptions.GetTemplatesException;
import com.github.cafdataprocessing.elastic.tools.exceptions.UnexpectedResponseException;
import com.google.common.net.UrlEscapers;

import jakarta.json.Json;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
import jakarta.json.stream.JsonParser;
import org.opensearch.client.json.jackson.JacksonJsonpMapper;
import org.opensearch.client.opensearch._types.mapping.TypeMapping;
import org.opensearch.client.opensearch.indices.GetTemplateResponse;
import org.opensearch.client.opensearch.indices.TemplateMapping;
import org.opensearch.client.util.ApiTypeHelper;

final class ElasticRequestHandler
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticRequestHandler.class);
    private final RestClient elasticClient;
    private final ObjectMapper objectMapper;

    public ElasticRequestHandler(final ElasticMappingUpdaterConfiguration schemaUpdaterConfig, final ObjectMapper mapper)
    {
        this.objectMapper = mapper;
        this.elasticClient = ElasticProvider.getClient(schemaUpdaterConfig.getElasticSettings());
    }

    Map getTemplates()
        throws IOException, GetTemplatesException
    {
        LOGGER.debug("Getting templates...");
        final Request request = new Request("GET", "/_template");
        final Response response = elasticClient.performRequest(request);

        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            try (final InputStream resultJsonStream = response.getEntity().getContent();
                final JsonParser jsonValueParser = Json.createParser(resultJsonStream)) {
                ApiTypeHelper.DANGEROUS_disableRequiredPropertiesCheck(true);
                final GetTemplateResponse getTemplatesResponse =
                    GetTemplateResponse._DESERIALIZER.deserialize(jsonValueParser, new JacksonJsonpMapper());
                final Map indexTemplates = getTemplatesResponse.result();
                ApiTypeHelper.DANGEROUS_disableRequiredPropertiesCheck(false);
                return indexTemplates;
            }
        } else {
            throw new GetTemplatesException(String.format("Error getting templates. Status code: %s, response: %s",
                                                          statusCode, EntityUtils.toString(response.getEntity())));
        }
    }

    List getIndexNames(final List indexNamePatterns) throws UnexpectedResponseException, IOException
    {
        LOGGER.debug("Getting index names matching pattern(s) : {}...", indexNamePatterns);
        if (indexNamePatterns == null || indexNamePatterns.isEmpty()) {
            return Collections.emptyList();
        }
        final String filter = "/" + String.join(",", indexNamePatterns);
        final Request request = new Request("GET", filter);

        try {
            final JsonNode responseNode = performRequest(request);

            final Iterable fieldNames = () -> responseNode.fieldNames();

            return StreamSupport.stream(fieldNames.spliterator(), false)
                .sorted()
                .collect(Collectors.toList());
        } catch (final ResponseException e) {
            final int statusCode = e.getResponse().getStatusLine().getStatusCode();
            if (statusCode == 404) {
                // No indexes matching template pattern
                return Collections.emptyList();
            } else {
                throw e;
            }
        }
    }

    public TypeMapping getIndexMapping(final String indexName) throws IOException, GetIndexException
    {
        LOGGER.debug("Getting index mapping for: {}...", indexName);
        final Request request = new Request("GET", "/" + UrlEscapers.urlPathSegmentEscaper().escape(indexName));
        final Response response = elasticClient.performRequest(request);

        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            final JsonReader jsonReader = Json.createReader(new StringReader(EntityUtils.toString(response.getEntity())));
            final JsonObject mappings = jsonReader.readObject().getJsonObject(indexName).getJsonObject("mappings");

            final JsonParser jsonMappingParser = Json.createParser(new StringReader(mappings.toString()));
            ApiTypeHelper.DANGEROUS_disableRequiredPropertiesCheck(true);
            final TypeMapping mapping = TypeMapping._DESERIALIZER.deserialize(jsonMappingParser, new JacksonJsonpMapper());
            ApiTypeHelper.DANGEROUS_disableRequiredPropertiesCheck(false);
            return mapping;
        } else {
            throw new GetIndexException(String.format("Error getting index '%s'. Status code: %s, response: %s",
                                                      indexName, statusCode, EntityUtils.toString(response.getEntity())));
        }
    }

    boolean updateIndexMapping(final String indexName, final Map mappings)
        throws IOException, UnexpectedResponseException
    {
        LOGGER.debug("Updating mapping of index {} with these changes {}...", indexName, mappings);
        final String mappingSource = objectMapper.writeValueAsString(mappings);
        final Request request = new Request("PUT", "/" + UrlEscapers.urlPathSegmentEscaper().escape(indexName) + "/_mapping");
        request.setJsonEntity(mappingSource);

        final Response response = elasticClient.performRequest(request);

        // Get the response entity
        final HttpEntity responseEntity = response.getEntity();

        // Get the Content-Type header
        final ContentType contentType = ContentType.get(responseEntity);
        if (contentType == null) {
            throw new UnexpectedResponseException("Failed to get the content type from the response entity");
        }

        // Check that the response is JSON
        if (!ContentType.APPLICATION_JSON.getMimeType().equals(contentType.getMimeType())) {
            throw new UnexpectedResponseException("JSON response expected but response type was " + contentType.getMimeType());
        }

        // Parse the response
        final JsonNode responseNode = StandardCharsets.UTF_8.equals(contentType.getCharset())
            ? objectMapper.readTree(responseEntity.getContent())
            : objectMapper.readTree(EntityUtils.toString(responseEntity));

        // Check that it is not null
        if (responseNode == null) {
            throw new UnexpectedResponseException("JSON response deserialized to null");
        }

        final int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            return true;
        } else {
            LOGGER.error("Index Mapping upadate status : {}", statusCode);
            return false;
        }
    }

    private JsonNode performRequest(final Request request) throws UnexpectedResponseException, IOException
    {
        final Response response = elasticClient.performRequest(request);

        // Get the response entity
        final HttpEntity responseEntity = response.getEntity();

        // Get the Content-Type header
        final ContentType contentType = ContentType.get(responseEntity);
        if (contentType == null) {
            throw new UnexpectedResponseException("Failed to get the content type from the response entity");
        }

        // Check that the response is JSON
        if (!ContentType.APPLICATION_JSON.getMimeType().equals(contentType.getMimeType())) {
            throw new UnexpectedResponseException("JSON response expected but response type was " + contentType.getMimeType());
        }

        // Parse the response
        final JsonNode responseNode = StandardCharsets.UTF_8.equals(contentType.getCharset())
            ? objectMapper.readTree(responseEntity.getContent())
            : objectMapper.readTree(EntityUtils.toString(responseEntity));

        // Check that it is not null
        if (responseNode == null) {
            throw new UnexpectedResponseException("JSON response deserialized to null");
        }

        return responseNode;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy