package com.workshare.msnos.usvc.api; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; import com.workshare.msnos.core.Agent; import com.workshare.msnos.core.protocols.ip.Endpoint; import com.workshare.msnos.core.protocols.ip.Network; import com.workshare.msnos.soup.json.Json; public class RestApi { private static final Logger log = LoggerFactory.getLogger(RestApi.class); public enum Type { @SerializedName("PUB") PUBLIC, @SerializedName("INT") INTERNAL, @SerializedName("HCK") HEALTHCHECK, @SerializedName("MHT") MSNOS_HTTP } private static final AtomicLong NEXT_ID = new AtomicLong(0); private final transient long id; private final String path; private final String host; private final int port; private final boolean sticky; private final Type type; private final int priority; private final AtomicInteger tempFaults; private boolean faulty; public RestApi(String path, int port) { this(path, port, null); } public RestApi(String path, int port, String host) { this(path, port, host, Type.PUBLIC, false); } public RestApi(String path, int port, String host, Type type, boolean sessionAffinity) { this(path, port, host, type, sessionAffinity, 0); } public RestApi(String path, int port, String host, Type type, boolean sessionAffinity, int priority) { if (path == null) { throw new IllegalArgumentException("path cannot be null"); } this.path = path; this.faulty = false; this.port = port; this.host = host; this.sticky = sessionAffinity; this.type = type; this.priority = priority; this.id = NEXT_ID.getAndIncrement(); tempFaults = new AtomicInteger(); } public RestApi asHealthCheck() { return new RestApi(path, port, host, Type.HEALTHCHECK, sticky, priority); } public RestApi asInternal() { return new RestApi(path, port, host, Type.INTERNAL, sticky, priority); } public RestApi asMsnosEndpoint() { return new RestApi(path, port, host, Type.MSNOS_HTTP, sticky, priority); } public RestApi withPriority(int priority) { return new RestApi(path, port, host, type, sticky, priority); } public RestApi onHost(String host) { return new RestApi(path, port, host, type, sticky, priority); } public RestApi onPort(int port) { return new RestApi(path, port, host, type, sticky, priority); } public RestApi withAffinity() { return new RestApi(path, port, host, type, true, priority); } public boolean hasAffinity() { return sticky; } public boolean isFaulty() { return faulty; } public RestApi markFaulty() { faulty = true; return this; } public void markWorking() { tempFaults.set(0); faulty = false; } public RestApi markTempFault() { tempFaults.incrementAndGet(); return this; } public int getTempFaults() { return tempFaults.get(); } public int getPriority() { return priority; } public String getPath() { return path; } public String getHost() { return host; } public int getPort() { return port; } public String getUrl() { String hostname = getHost(); if (hostname == null) hostname = "*"; String prefix = ""; String path = getPath(); if (!path.startsWith("/")) prefix = "/"; return String.format("http://%s:%d%s%s", hostname, getPort(), prefix, getPath()); } public long getId() { return id; } public Type getType() { return type; } @Override public int hashCode() { int result = path.hashCode(); int prime = 31; result = prime * result + port; result = prime * result + (sticky ? 1231 : 1237); result = prime * result + type.hashCode(); result = prime * result + ((host == null) ? 0 : host.hashCode()); return result; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; RestApi restApi = (RestApi) o; if (port != restApi.port) return false; if (sticky != restApi.sticky) return false; if (!path.equals(restApi.path)) return false; if (type != restApi.type) return false; if (!host.equals(restApi.host)) return false; return true; } @Override public String toString() { try { JsonObject obj = (JsonObject)Json.toJsonTree(this); obj.addProperty("faulty",this.isFaulty()); obj.addProperty("tempfaults",this.getTempFaults()); return obj.toString(); } catch (Exception any) { try { return getUrl(); } catch (Exception e) { return super.toString(); } } } public static Set<RestApi> ensureHostIsPresent(Agent agent, Set<RestApi> apis) { Set<RestApi> result = new HashSet<RestApi>(); for (RestApi api : apis) { if (api.getHost() == null || api.getHost().isEmpty()) { boolean found = false; for (Endpoint endpoint : agent.getEndpoints()) { Network network = endpoint.getNetwork(); result.add(api.onHost(network.getHostString())); found = true; } if (!found) { log.error("{} API received but agent with no endpoints!!! {}", api, agent); } } else { result.add(api); } } return result; } }