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

com.github.housepower.jdbc.ClickhouseJdbcUrlParser Maven / Gradle / Ivy

/*
 * 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.housepower.jdbc;

import com.github.housepower.exception.InvalidValueException;
import com.github.housepower.log.Logger;
import com.github.housepower.log.LoggerFactory;
import com.github.housepower.misc.Validate;
import com.github.housepower.settings.SettingKey;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ClickhouseJdbcUrlParser {
    public static final String JDBC_PREFIX = "jdbc:";
    public static final String CLICKHOUSE_PREFIX = "clickhouse:";
    public static final String JDBC_CLICKHOUSE_PREFIX = JDBC_PREFIX + CLICKHOUSE_PREFIX;

    public static final String HOST_DELIMITER = ",";
    public static final String PORT_DELIMITER = ":";

    /**
     * Jdbc Url sames like:
     * '//[host1][:port1],[host2][:port2],[host3][:port3]]...[/[database]][?propertyName1=propertyValue1[&propertyName2=propertyValue2]...]'
     *
     * Default_port is used when port does not exist.
     */
    public static final Pattern CONNECTION_PATTERN = Pattern.compile("//(?([^/?:,\\s]+(:\\d+)?)(,[^/?:,\\s]+(:\\d+)?)*)" // hosts: required; starts with "//" followed by any char except "/", "?"
            + "(?:/(?([a-zA-Z0-9_]+)))?" // database: optional; starts with "/", and then followed by any char except "?"
            + "(?:\\?(?.*))?"); // properties: optional; starts with "?", and then followed by any char

    private static final Logger LOG = LoggerFactory.getLogger(ClickhouseJdbcUrlParser.class);

    public static Map parseJdbcUrl(String jdbcUrl) {
        String uri = jdbcUrl.substring(JDBC_CLICKHOUSE_PREFIX.length());
        Matcher matcher = CONNECTION_PATTERN.matcher(uri);
        if (!matcher.matches()) {
            throw new InvalidValueException("Connection is not support");
        }

        Map settings = new HashMap<>();

        String hosts = matcher.group("hosts");
        String database = matcher.group("database");
        String properties = matcher.group("properties");

        if (hosts.contains(HOST_DELIMITER)) { // multi-host
            settings.put(SettingKey.host, hosts);
        } else { // standard-host
            String[] hostAndPort = hosts.split(PORT_DELIMITER, 2);

            settings.put(SettingKey.host, hostAndPort[0]);

            if (hostAndPort.length == 2) {
                if (Integer.parseInt(hostAndPort[1]) == 8123) {
                    LOG.warn("8123 is default HTTP port, you may connect with error protocol!");
                }
                settings.put(SettingKey.port, Integer.parseInt(hostAndPort[1]));
            }
        }

        settings.put(SettingKey.database, database);
        settings.putAll(extractQueryParameters(properties));

        return settings;
    }

    public static Map parseProperties(Properties properties) {
        Map settings = new HashMap<>();

        for (String name : properties.stringPropertyNames()) {
            String value = properties.getProperty(name);

            parseSetting(settings, name, value);
        }

        return settings;
    }

    public static Map extractQueryParameters(String queryParameters) {
        Map parameters = new HashMap<>();
        StringTokenizer tokenizer = new StringTokenizer(queryParameters == null ? "" : queryParameters, "&");

        while (tokenizer.hasMoreTokens()) {
            String[] queryParameter = tokenizer.nextToken().split("=", 2);
            Validate.ensure(queryParameter.length == 2,
                    "ClickHouse JDBC URL Parameter '" + queryParameters + "' Error, Expected '='.");

            String name = queryParameter[0];
            String value = queryParameter[1];

            parseSetting(parameters, name, value);
        }
        return parameters;
    }

    private static void parseSetting(Map settings, String name, String value) {
        SettingKey settingKey = SettingKey.definedSettingKeys().get(name.toLowerCase(Locale.ROOT));
        if (settingKey != null) {
            settings.put(settingKey, settingKey.type().deserializeURL(value));
        } else {
            LOG.warn("ignore undefined setting: {}={}", name, value);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy