package com.griddynamics.jagger.invoker.v2;
import com.google.common.base.Preconditions;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.HttpsURL;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
import static com.griddynamics.jagger.invoker.v2.JHttpEndpoint.Protocol.HTTP;
import static com.griddynamics.jagger.invoker.v2.JHttpEndpoint.Protocol.HTTPS;
import static java.lang.String.format;
import static org.apache.commons.lang.StringUtils.equalsIgnoreCase;
import static org.springframework.web.util.UriComponentsBuilder.fromUri;
import static org.springframework.web.util.UriComponentsBuilder.newInstance;
/**
* An object that represents HTTP-endpoint. It consists of {@link JHttpEndpoint#protocol},
* {@link JHttpEndpoint#hostname} and {@link JHttpEndpoint#port} fields. <p>
*
* @author Anton Antonenko
* @since 2.0
*
* @ingroup Main_Http_group
*/
public class JHttpEndpoint implements Serializable {
public static final Protocol DEF_PROTOCOL = Protocol.HTTP;
/**
* Enum representing HTTP and HTTPS protocols
*/
public enum Protocol {
HTTP, HTTPS
}
private Protocol protocol = DEF_PROTOCOL;
private String hostname;
private int port = HttpURL.DEFAULT_PORT;
/**
* Parses given uri and sets {@link JHttpEndpoint#protocol}, {@link JHttpEndpoint#hostname} and {@link JHttpEndpoint#port} fields.
*
* @param uri URI to parse
*/
@SuppressWarnings("unused")
public JHttpEndpoint(URI uri) {
try {
URL url = uri.toURL();
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
}
if (equalsIgnoreCase(uri.getScheme(), HTTP.name())) {
this.protocol = HTTP;
this.port = HttpURL.DEFAULT_PORT;
} else if (equalsIgnoreCase(uri.getScheme(), HTTPS.name())) {
this.protocol = HTTPS;
this.port = HttpsURL.DEFAULT_PORT;
} else {
throw new IllegalArgumentException(format("Protocol of uri '%s' is unsupported!", uri));
}
this.hostname = uri.getHost();
if (uri.getPort() > 0) {
this.port = uri.getPort();
}
}
/**
* @param protocol protocol of endpoint
* @param hostname hostname of endpoint
* @param port port of endpoint
*/
public JHttpEndpoint(Protocol protocol, String hostname, int port) {
Objects.requireNonNull(protocol);
this.protocol = protocol;
if (org.springframework.util.StringUtils.isEmpty(hostname)) {
throw new IllegalArgumentException(format("hostname must non-empty. Provided value: %s", hostname));
}
this.hostname = hostname;
if (port <= 0) {
throw new IllegalArgumentException(format("port number must be > 0. Provided value: %s", port));
}
this.port = port;
}
/**
* @param hostname hostname of endpoint
* @param port port of endpoint
*/
public JHttpEndpoint(String hostname, int port) {
this(DEF_PROTOCOL, hostname, port);
}
/**
* @param endpointURL string with url to be passed to {@link JHttpEndpoint#JHttpEndpoint(URI)} constructor
*/
public JHttpEndpoint(String endpointURL) {
this(URI.create(endpointURL));
}
public Protocol getProtocol() {
return protocol;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
/**
* @return {@link URI} based on {@link JHttpEndpoint#protocol},
* {@link JHttpEndpoint#hostname} and {@link JHttpEndpoint#port} fields values.
*/
public URI getURI() {
Preconditions.checkNotNull(hostname, "Hostname is null!");
if (protocol == null) {
protocol = DEF_PROTOCOL;
}
return newInstance().scheme(protocol.name().toLowerCase()).host(hostname).port(port).build().toUri();
}
/**
* @param path path to be added to URI
* @return {@link URI} based on {@link JHttpEndpoint#protocol},
* {@link JHttpEndpoint#hostname} and {@link JHttpEndpoint#port} fields values with <b>path</b> added.
*/
public URI getURI(String path) {
URI oldUri = getURI();
if (StringUtils.isEmpty(path)) {
return oldUri;
}
return fromUri(oldUri).path(path).build().toUri();
}
/**
* @param queryParams query parameters to be added to URI
* @return {@link URI} based on {@link JHttpEndpoint#protocol},
* {@link JHttpEndpoint#hostname} and {@link JHttpEndpoint#port} fields values with <b>queryParams</b> added.
*/
public URI getURI(Map<String, String> queryParams) {
URI uri = getURI();
if (MapUtils.isEmpty(queryParams)) {
return uri;
}
return appendParameters(uri, queryParams);
}
/**
* @param path path to be added to URI
* @param queryParams query parameters to be added to URI
* @return {@link URI} based on {@link JHttpEndpoint#protocol},
* {@link JHttpEndpoint#hostname} and {@link JHttpEndpoint#port} fields values with <b>path</b> and <b>queryParams</b> added.
*/
public URI getURI(String path, Map<String, String> queryParams) {
URI uri = getURI(path);
if (MapUtils.isEmpty(queryParams)) {
return uri;
}
return appendParameters(uri, queryParams);
}
/**
* @param oldUri base {@link URI}
* @param queryParams query parameters to be added to {@link URI}
* @return {@link URI} based on oldUri with <b>queryParams</b> added.
*/
public static URI appendParameters(URI oldUri, Map<String, String> queryParams) {
MultiValueMap<String, String> localQueryParams = new LinkedMultiValueMap<>();
queryParams.entrySet().forEach(entry -> localQueryParams.add(entry.getKey(), entry.getValue()));
return fromUri(oldUri).queryParams(localQueryParams).build().toUri();
}
public static JHttpEndpoint copyOf(JHttpEndpoint jHttpEndpoint) {
if (jHttpEndpoint == null)
return null;
return new JHttpEndpoint(jHttpEndpoint.getURI());
}
@Override
public String toString() {
return "JHttpEndpoint{" +
"protocol=" + protocol +
", hostname='" + hostname + '\'' +
", port=" + port +
'}';
}
}