org.graylog2.indexer.cluster.jest.JestUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.graylog2.indexer.cluster.jest.JestUtils.java

Source

/**
 * This file is part of Graylog.
 *
 * Graylog is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Graylog is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Graylog.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.graylog2.indexer.cluster.jest;

import com.google.gson.JsonObject;
import io.searchbox.action.Action;
import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.client.http.JestHttpClient;
import org.apache.http.client.config.RequestConfig;
import org.graylog2.indexer.ElasticsearchException;
import org.graylog2.indexer.FieldTypeException;
import org.graylog2.indexer.IndexNotFoundException;
import org.graylog2.indexer.QueryParsingException;
import org.graylog2.indexer.gson.GsonUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static org.graylog2.indexer.gson.GsonUtils.asInteger;
import static org.graylog2.indexer.gson.GsonUtils.asJsonArray;
import static org.graylog2.indexer.gson.GsonUtils.asJsonObject;
import static org.graylog2.indexer.gson.GsonUtils.asString;

public class JestUtils {
    private JestUtils() {
    }

    public static <T extends JestResult> T execute(JestClient client, RequestConfig requestConfig,
            Action<T> request, Supplier<String> errorMessage) {
        final T result;
        try {
            if (client instanceof JestHttpClient) {
                result = ((JestHttpClient) client).execute(request, requestConfig);
            } else {
                result = client.execute(request);
            }
        } catch (IOException e) {
            throw new ElasticsearchException(errorMessage.get(), e);
        }

        if (result.isSucceeded()) {
            return result;
        } else {
            throw specificException(errorMessage, result.getJsonObject());
        }
    }

    public static <T extends JestResult> T execute(JestClient client, Action<T> request,
            Supplier<String> errorMessage) {
        return execute(client, null, request, errorMessage);
    }

    private static ElasticsearchException specificException(Supplier<String> errorMessage, JsonObject jsonObject) {
        final List<JsonObject> rootCauses = extractRootCauses(jsonObject);
        final List<String> reasons = extractReasons(rootCauses);

        for (JsonObject rootCause : rootCauses) {
            final String type = asString(rootCause.get("type"));
            if (type == null) {
                continue;
            }
            switch (type) {
            case "query_parsing_exception":
                return buildQueryParsingException(errorMessage, rootCause, reasons);
            case "index_not_found_exception":
                final String indexName = asString(rootCause.get("resource.id"));
                return buildIndexNotFoundException(errorMessage, indexName);
            case "illegal_argument_exception":
                final String reason = asString(rootCause.get("reason"));
                if (reason != null && reason.startsWith("Expected numeric type on field")) {
                    return buildFieldTypeException(errorMessage, reason);
                }
                break;
            }
        }

        if (reasons.isEmpty()) {
            return new ElasticsearchException(errorMessage.get(), Collections.singletonList(jsonObject.toString()));
        }

        return new ElasticsearchException(errorMessage.get(), reasons);
    }

    private static FieldTypeException buildFieldTypeException(Supplier<String> errorMessage, String reason) {
        return new FieldTypeException(errorMessage.get(), reason);
    }

    private static List<String> extractReasons(List<JsonObject> rootCauses) {
        return rootCauses.stream().map(rootCause -> asString(rootCause.get("reason"))).collect(Collectors.toList());
    }

    private static List<JsonObject> extractRootCauses(JsonObject jsonObject) {
        return Optional.of(jsonObject).map(json -> asJsonObject(json.get("error")))
                .map(error -> asJsonArray(error.get("root_cause"))).map(Iterable::spliterator)
                .map(x -> StreamSupport.stream(x, false)).orElse(Stream.empty()).map(GsonUtils::asJsonObject)
                .collect(Collectors.toList());
    }

    private static QueryParsingException buildQueryParsingException(Supplier<String> errorMessage,
            JsonObject rootCause, List<String> reasons) {
        final Integer line = asInteger(rootCause.get("line"));
        final Integer column = asInteger(rootCause.get("col"));
        final String index = asString(rootCause.get("index"));

        return new QueryParsingException(errorMessage.get(), line, column, index, reasons);
    }

    private static IndexNotFoundException buildIndexNotFoundException(Supplier<String> errorMessage, String index) {
        return new IndexNotFoundException(errorMessage.get(), Collections
                .singletonList("Index not found for query: " + index + ". Try recalculating your index ranges."));
    }
}