blob: f489b56b1006c83e72d6bc84ffc51b1193b9d988 [file] [log] [blame]
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2021 MariaDB Corporation Ab
package org.mariadb.jdbc;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.mariadb.jdbc.export.HaMode;
/** Host entry */
public class HostAddress {
/** host address */
public final String host;
/** port */
public int port;
/** primary node */
public Boolean primary;
/**
* Constructor.
*
* @param host host
* @param port port
* @param primary is primary
*/
private HostAddress(String host, int port, Boolean primary) {
this.host = host;
this.port = port;
this.primary = primary;
}
/**
* Create a Host without knowledge of primary/replica goal
*
* @param host host (DNS/IP)
* @param port port
* @return host
*/
public static HostAddress from(String host, int port) {
return new HostAddress(host, port, null);
}
/**
* Create a Host
*
* @param host host (DNS/IP)
* @param port port
* @param primary is primary
* @return host
*/
public static HostAddress from(String host, int port, boolean primary) {
return new HostAddress(host, port, primary);
}
/**
* parse - parse server addresses from the URL fragment.
*
* @param spec list of endpoints in one of the forms 1 - host1,....,hostN:port (missing port
* default to MariaDB default 3306 2 - host:port,...,host:port
* @param haMode High availability mode
* @throws SQLException for wrong spec
* @return parsed endpoints
*/
public static List<HostAddress> parse(String spec, HaMode haMode) throws SQLException {
if ("".equals(spec)) {
return new ArrayList<>(0);
}
String[] tokens = spec.trim().split(",");
int size = tokens.length;
List<HostAddress> arr = new ArrayList<>(size);
for (int i = 0; i < tokens.length; i++) {
String token = tokens[i];
if (token.startsWith("address=")) {
arr.add(parseParameterHostAddress(token, haMode, i == 0));
} else {
arr.add(parseSimpleHostAddress(token, haMode, i == 0));
}
}
return arr;
}
private static HostAddress parseSimpleHostAddress(String str, HaMode haMode, boolean first)
throws SQLException {
String host;
int port = 3306;
if (str.charAt(0) == '[') {
/* IPv6 addresses in URLs are enclosed in square brackets */
int ind = str.indexOf(']');
host = str.substring(1, ind);
if (ind != (str.length() - 1) && str.charAt(ind + 1) == ':') {
port = getPort(str.substring(ind + 2));
}
} else if (str.contains(":")) {
/* Parse host:port */
String[] hostPort = str.split(":");
host = hostPort[0];
port = getPort(hostPort[1]);
} else {
/* Just host name is given */
host = str;
}
boolean primary = haMode != HaMode.REPLICATION || first;
return new HostAddress(host, port, primary);
}
private static int getPort(String portString) throws SQLException {
try {
return Integer.parseInt(portString);
} catch (NumberFormatException nfe) {
throw new SQLException("Incorrect port value : " + portString);
}
}
private static HostAddress parseParameterHostAddress(String str, HaMode haMode, boolean first)
throws SQLException {
String host = null;
int port = 3306;
Boolean primary = null;
String[] array = str.replace(" ", "").split("(?=\\()|(?<=\\))");
for (int i = 1; i < array.length; i++) {
String[] token = array[i].replace("(", "").replace(")", "").trim().split("=");
if (token.length != 2) {
throw new IllegalArgumentException(
"Invalid connection URL, expected key=value pairs, found " + array[i]);
}
String key = token[0].toLowerCase();
String value = token[1].toLowerCase();
switch (key) {
case "host":
host = value.replace("[", "").replace("]", "");
break;
case "port":
port = getPort(value);
break;
case "type":
if ("master".equalsIgnoreCase(value) || "primary".equalsIgnoreCase(value)) {
primary = true;
} else if ("slave".equalsIgnoreCase(value) || "replica".equalsIgnoreCase(value)) {
primary = false;
} else {
throw new SQLException(
String.format("Wrong type value %s (possible value primary/replica)", array[i]));
}
break;
}
}
if (primary == null) {
if (haMode == HaMode.REPLICATION) {
primary = first;
} else {
primary = true;
}
}
return new HostAddress(host, port, primary);
}
@Override
public String toString() {
return String.format(
"address=(host=%s)(port=%s)%s",
host, port, ((primary != null) ? ("(type=" + (primary ? "primary)" : "replica)")) : ""));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HostAddress that = (HostAddress) o;
return port == that.port
&& Objects.equals(host, that.host)
&& Objects.equals(primary, that.primary);
}
@Override
public int hashCode() {
return Objects.hash(host, port, primary);
}
}