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

org.bigraphs.spring.data.cdo.CdoServerConnectionString Maven / Gradle / Ivy

There is a newer version: 0.7.2
Show newest version
package org.bigraphs.spring.data.cdo;

import org.bigraphs.spring.data.cdo.config.CdoCredentials;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;

/**
 * Source code is mostly adapted from {@code com.mongodb.ConnectionString} of the
 * mongo-java-driver library.
 *
 * @author Dominik Grzelak
 * @see https://mongodb.github.io/mongo-java-driver/3.8/javadoc/com/mongodb/ConnectionString.html
 */
public class CdoServerConnectionString {
    private static final String CDO_PROTOCOL_PREFIX = "cdo://";
    private static final String UTF_8 = "UTF-8";

    private String repoName;

    private int port;

    private final CdoCredentials credential;

    private String host;

    private final List hosts;

    private String connectionString;

    public CdoServerConnectionString(final String connectionString) {
        this.connectionString = connectionString;
        boolean isCDOProtocol = connectionString.startsWith(CDO_PROTOCOL_PREFIX);
        if (!isCDOProtocol) {
            throw new IllegalArgumentException(format("The connection string is invalid. "
                    + "Connection strings must start with either '%s'", CDO_PROTOCOL_PREFIX));
        }

        String unprocessedConnectionString;
        unprocessedConnectionString = connectionString.substring(CDO_PROTOCOL_PREFIX.length());

        // Split out the user and host information
        String userAndHostInformation;
        int idx = unprocessedConnectionString.indexOf("/");
        if (idx == -1) {
            userAndHostInformation = unprocessedConnectionString;
            unprocessedConnectionString = "";
        } else {
            userAndHostInformation = unprocessedConnectionString.substring(0, idx);
            unprocessedConnectionString = unprocessedConnectionString.substring(idx + 1);
        }

        // Split the user and host information
        String userInfo;
        String hostIdentifier;
        String userName = null;
        char[] password = null;
        idx = userAndHostInformation.lastIndexOf("@");
        if (idx > 0) {
            userInfo = userAndHostInformation.substring(0, idx).replace("+", "%2B");
            hostIdentifier = userAndHostInformation.substring(idx + 1);
            int colonCount = countOccurrences(userInfo, ":");
            if (userInfo.contains("@") || colonCount > 1) {
                throw new IllegalArgumentException("The connection string contains invalid user information. "
                        + "If the username or password contains a colon (:) or an at-sign (@) then it must be urlencoded");
            }
            if (colonCount == 0) {
                userName = urldecode(userInfo);
            } else {
                idx = userInfo.indexOf(":");
                userName = urldecode(userInfo.substring(0, idx));
                password = urldecode(userInfo.substring(idx + 1), true).toCharArray();
            }
        } else {
            hostIdentifier = userAndHostInformation;
        }

        this.hosts = unmodifiableList(parseHosts(asList(hostIdentifier.split(","))));
        if (this.hosts.size() > 0) {
            String[] splitted = this.hosts.get(0).split(":");
            this.host = splitted[0];
            this.port = Integer.parseInt(splitted[1]);
        }

        idx = unprocessedConnectionString.indexOf("/");
        if (unprocessedConnectionString.length() == 0) {
            throw new IllegalArgumentException("The connection string contains no repository details.");
        }

        String repoResourcePathString;
        if (idx == -1) {
            this.repoName = unprocessedConnectionString;
        } else {
            this.repoName = unprocessedConnectionString.substring(0, idx);
            if (this.repoName.replaceAll("/", "").length() == 0) {
                throw new IllegalArgumentException("The connection string contains no repository details.");
            }
            repoResourcePathString = unprocessedConnectionString.substring(idx, unprocessedConnectionString.length());
        }

        credential = new CdoCredentials(userName, password, "");

    }

    private int countOccurrences(final String haystack, final String needle) {
        return haystack.length() - haystack.replace(needle, "").length();
    }

    private String urldecode(final String input) {
        return urldecode(input, false);
    }

    private String urldecode(final String input, final boolean password) {
        try {
            return URLDecoder.decode(input, UTF_8);
        } catch (UnsupportedEncodingException e) {
            if (password) {
                throw new IllegalArgumentException("The connection string contained unsupported characters in the password.");
            } else {
                throw new IllegalArgumentException(format("The connection string contained unsupported characters: '%s'."
                        + "Decoding produced the following error: %s", input, e.getMessage()));
            }
        }
    }

    private List parseHosts(final List rawHosts) {
        if (rawHosts.size() == 0) {
            throw new IllegalArgumentException("The connection string must contain at least one host");
        }
        List hosts = new ArrayList();
        for (String host : rawHosts) {
            if (host.length() == 0) {
                throw new IllegalArgumentException(format("The connection string contains an empty host '%s'. ", rawHosts));
            } else if (host.endsWith(".sock")) {
                host = urldecode(host);
            } else if (host.startsWith("[")) {
                if (!host.contains("]")) {
                    throw new IllegalArgumentException(format("The connection string contains an invalid host '%s'. "
                            + "IPv6 address literals must be enclosed in '[' and ']' according to RFC 2732", host));
                }
                int idx = host.indexOf("]:");
                if (idx != -1) {
                    validatePort(host, host.substring(idx + 2));
                }
            } else {
                int colonCount = countOccurrences(host, ":");
                if (colonCount > 1) {
                    throw new IllegalArgumentException(format("The connection string contains an invalid host '%s'. "
                            + "Reserved characters such as ':' must be escaped according RFC 2396. "
                            + "Any IPv6 address literal must be enclosed in '[' and ']' according to RFC 2732.", host));
                } else if (colonCount == 1) {
                    validatePort(host, host.substring(host.indexOf(":") + 1));
                }
            }
            hosts.add(host);
        }
        Collections.sort(hosts);
        return hosts;
    }

    private void validatePort(final String host, final String port) {
        boolean invalidPort = false;
        try {
            int portInt = Integer.parseInt(port);
            if (portInt <= 0 || portInt > 65535) {
                invalidPort = true;
            }
        } catch (NumberFormatException e) {
            invalidPort = true;
        }
        if (invalidPort) {
            throw new IllegalArgumentException(format("The connection string contains an invalid host '%s'. "
                    + "The port '%s' is not a valid, it must be an integer between 0 and 65535", host, port));
        }
    }

    public List getHosts() {
        return hosts;
    }

    public CdoCredentials getCredential() {
        return credential;
    }

    public String getRepoName() {
        return repoName;
    }

    public String getUsername() {
        return credential != null ? credential.getUserName() : null;
    }

    public char[] getPassword() {
        return credential != null ? credential.getPassword() : null;
    }

    public String getServer() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public String getConnectionString() {
        return connectionString;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy