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

com.clickhouse.client.http.ClickHouseHttpClient Maven / Gradle / Ivy

There is a newer version: 0.7.1-patch1
Show newest version
package com.clickhouse.client.http;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionException;

import com.clickhouse.client.AbstractClient;
import com.clickhouse.client.ClickHouseConfig;
import com.clickhouse.client.ClickHouseException;
import com.clickhouse.client.ClickHouseNode;
import com.clickhouse.client.ClickHouseProtocol;
import com.clickhouse.client.ClickHouseRequest;
import com.clickhouse.client.ClickHouseResponse;
import com.clickhouse.client.ClickHouseTransaction;
import com.clickhouse.client.ClickHouseStreamResponse;
import com.clickhouse.client.http.config.ClickHouseHttpOption;
import com.clickhouse.config.ClickHouseOption;
import com.clickhouse.logging.Logger;
import com.clickhouse.logging.LoggerFactory;

public class ClickHouseHttpClient extends AbstractClient {
    private static final Logger log = LoggerFactory.getLogger(ClickHouseHttpClient.class);

    static final List SUPPORTED = Collections.singletonList(ClickHouseProtocol.HTTP);

    @Override
    protected boolean checkConnection(ClickHouseHttpConnection connection, ClickHouseNode requestServer,
            ClickHouseNode currentServer, ClickHouseRequest request) {
        // return false to suggest creating a new connection
        return connection != null && connection.isReusable() && requestServer.isSameEndpoint(currentServer);
    }

    @Override
    protected boolean checkHealth(ClickHouseNode server, int timeout) {
        return getConnection(connect(server)).ping(timeout);
    }

    @Override
    protected Collection getSupportedProtocols() {
        return SUPPORTED;
    }

    @Override
    protected ClickHouseHttpConnection newConnection(ClickHouseHttpConnection connection, ClickHouseNode server,
            ClickHouseRequest request) {
        if (connection != null && connection.isReusable()) {
            closeConnection(connection, false);
        }

        try {
            return ClickHouseHttpConnectionFactory.createConnection(server, request, getExecutor());
        } catch (IOException e) {
            throw new CompletionException(e);
        }
    }

    @Override
    protected void closeConnection(ClickHouseHttpConnection connection, boolean force) {
        try {
            connection.close();
        } catch (Exception e) {
            log.warn("Failed to close http connection due to: %s", e.getMessage());
        }
    }

    protected String buildQueryParams(Map params) {
        if (params == null || params.isEmpty()) {
            return "";
        }

        StringBuilder builder = new StringBuilder();
        for (Map.Entry entry : params.entrySet()) {
            builder.append(ClickHouseHttpConnection.urlEncode(entry.getKey(), StandardCharsets.UTF_8)).append('=')
                    .append(ClickHouseHttpConnection.urlEncode(entry.getValue(), StandardCharsets.UTF_8)).append('&');
        }

        if (builder.length() > 0) {
            builder.setLength(builder.length() - 1);
        }
        return builder.toString();
    }

    @Override
    protected ClickHouseResponse send(ClickHouseRequest sealedRequest) throws ClickHouseException, IOException {
        ClickHouseHttpConnection conn = getConnection(sealedRequest);

        List stmts = sealedRequest.getStatements(false);
        int size = stmts.size();
        String sql;
        if (size == 0) {
            throw new IllegalArgumentException("At least one SQL statement is required for execution");
        } else if (size > 1) {
            throw new IllegalArgumentException("Expect one SQL statement to execute but we got " + size);
        } else {
            sql = stmts.get(0);
        }

        log.debug("Query: %s", sql);
        final ClickHouseConfig config = sealedRequest.getConfig();
        final ClickHouseHttpResponse httpResponse;
        final ClickHouseTransaction tx = sealedRequest.getTransaction();
        final Runnable postAction = tx != null && tx.isImplicit()
                ? () -> {
                    try {
                        tx.commit();
                    } catch (ClickHouseException e) {
                        throw new UncheckedIOException(new IOException(e.getMessage()));
                    }
                }
                : null;
        if (conn.isReusable()) {
            ClickHouseNode server = sealedRequest.getServer();
            httpResponse = conn.post(config, sql, sealedRequest.getInputStream().orElse(null),
                    sealedRequest.getExternalTables(), sealedRequest.getOutputStream().orElse(null),
                    ClickHouseHttpConnection.buildUrl(server.getBaseUri(), sealedRequest),
                    ClickHouseHttpConnection.createDefaultHeaders(config, server, conn.getUserAgent()),
                    postAction);
        } else {
            httpResponse = conn.post(config, sql, sealedRequest.getInputStream().orElse(null),
                    sealedRequest.getExternalTables(), sealedRequest.getOutputStream().orElse(null), null, null,
                    postAction);
        }
        return ClickHouseStreamResponse.of(httpResponse.getConfig(sealedRequest), httpResponse.getInputStream(),
                sealedRequest.getSettings(), null, httpResponse.summary);
    }

    @Override
    public final Class getOptionClass() {
        return ClickHouseHttpOption.class;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy