public final class TLSConfig {

	public enum KeyStoreInstanceType {
		JKS, JCEKS, PKCS12, PKCS11, DKS
	}

	private final KeyStoreInstanceType keyStoreInstanceType;
	private final String certificatePath;
	private final String certificatePassword;
	private final String keyStorePath;
	private final String keyStorePassword;

	public TLSConfig(KeyStoreInstanceType keyStoreInstanceType, String certificatePath, String certificatePassword, String keyStorePath,
					 String keyStorePassword) {
		this.keyStoreInstanceType = keyStoreInstanceType;
		this.certificatePath = certificatePath;
		this.certificatePassword = certificatePassword;
		this.keyStorePath = keyStorePath;
		this.keyStorePassword = keyStorePassword;
	}

	public KeyStoreInstanceType getKeyStoreInstanceType() {
		return keyStoreInstanceType;
	}

	public String getCertificatePath() {
		return certificatePath;
	}

	public String getCertificatePassword() {
		return certificatePassword;
	}

	public String getKeyStorePath() {
		return keyStorePath;
	}

	public String getKeyStorePassword() {
		return keyStorePassword;
	}
} public final class AclConsulClient implements AclClient {

	private final ConsulRawClient rawClient;

	public AclConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public AclConsulClient() {
		this(new ConsulRawClient());
	}

	public AclConsulClient(TLSConfig tlsConfig) {
		this(new ConsulRawClient(tlsConfig));
	}

	public AclConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public AclConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public AclConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	public AclConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<String> aclCreate(NewAcl newAcl, String token) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		String json = GsonFactory.getGson().toJson(newAcl);
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/acl/create", json, tokenParams);

		if (httpResponse.getStatusCode() == 200) {
			Map<String, String> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<Map<String, String>>() {
			}.getType());
			return new Response<String>(value.get("ID"), httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> aclUpdate(UpdateAcl updateAcl, String token) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		String json = GsonFactory.getGson().toJson(updateAcl);
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/acl/update", json, tokenParams);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> aclDestroy(String aclId, String token) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/acl/destroy/" + aclId, "", tokenParams);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Acl> getAcl(String id) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/acl/info/" + id);

		if (httpResponse.getStatusCode() == 200) {
			List<Acl> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Acl>>() {
			}.getType());

			if (value.isEmpty()) {
				return new Response<Acl>(null, httpResponse);
			} else if (value.size() == 1) {
				return new Response<Acl>(value.get(0), httpResponse);
			} else {
				throw new ConsulException("Strange response (list size=" + value.size() + ")");
			}
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<String> aclClone(String aclId, String token) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/acl/clone/" + aclId, "", tokenParams);

		if (httpResponse.getStatusCode() == 200) {
			Map<String, String> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<Map<String, String>>() {
			}.getType());
			return new Response<String>(value.get("ID"), httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Acl>> getAclList(String token) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/acl/list", tokenParams);

		if (httpResponse.getStatusCode() == 200) {
			List<Acl> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Acl>>() {
			}.getType());
			return new Response<List<Acl>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

} public class Acl {

	@SerializedName("CreateIndex")
	private long createIndex;

	@SerializedName("ModifyIndex")
	private long modifyIndex;

	@SerializedName("ID")
	private String id;

	@SerializedName("Name")
	private String name;

	@SerializedName("Type")
	private AclType type;

	@SerializedName("Rules")
	private String rules;

	public long getCreateIndex() {
		return createIndex;
	}

	public void setCreateIndex(long createIndex) {
		this.createIndex = createIndex;
	}

	public long getModifyIndex() {
		return modifyIndex;
	}

	public void setModifyIndex(long modifyIndex) {
		this.modifyIndex = modifyIndex;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public AclType getType() {
		return type;
	}

	public void setType(AclType type) {
		this.type = type;
	}

	public String getRules() {
		return rules;
	}

	public void setRules(String rules) {
		this.rules = rules;
	}

	@Override
	public String toString() {
		return "Acl{" +
				"createIndex=" + createIndex +
				", modifyIndex=" + modifyIndex +
				", id='" + id + '\'' +
				", name='" + name + '\'' +
				", type=" + type +
				", rules='" + rules + '\'' +
				'}';
	}
} public class NewAcl {

	@SerializedName("Name")
	private String name;

	@SerializedName("Type")
	private AclType type;

	@SerializedName("Rules")
	private String rules;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public AclType getType() {
		return type;
	}

	public void setType(AclType type) {
		this.type = type;
	}

	public String getRules() {
		return rules;
	}

	public void setRules(String rules) {
		this.rules = rules;
	}

	@Override
	public String toString() {
		return "NewAcl{" +
				"name='" + name + '\'' +
				", type=" + type +
				", rules='" + rules + '\'' +
				'}';
	}
} public class UpdateAcl {

	@SerializedName("ID")
	private String id;

	@SerializedName("Name")
	private String name;

	@SerializedName("Type")
	private AclType type;

	@SerializedName("Rules")
	private String rules;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public AclType getType() {
		return type;
	}

	public void setType(AclType type) {
		this.type = type;
	}

	public String getRules() {
		return rules;
	}

	public void setRules(String rules) {
		this.rules = rules;
	}

	@Override
	public String toString() {
		return "UpdateAcl{" +
				"id='" + id + '\'' +
				", name='" + name + '\'' +
				", type=" + type +
				", rules='" + rules + '\'' +
				'}';
	}
} public interface AgentClient {

	public Response<Map<String, Check>> getAgentChecks();

	public Response<Map<String, Service>> getAgentServices();

	public Response<List<Member>> getAgentMembers();

	public Response<Self> getAgentSelf();
	
	public Response<Self> getAgentSelf(String token);

	public Response<Void> agentSetMaintenance(boolean maintenanceEnabled);

	public Response<Void> agentSetMaintenance(boolean maintenanceEnabled, String reason);

	public Response<Void> agentJoin(String address, boolean wan);

	public Response<Void> agentForceLeave(String node);

	public Response<Void> agentCheckRegister(NewCheck newCheck);

	public Response<Void> agentCheckRegister(NewCheck newCheck, String token);

	public Response<Void> agentCheckDeregister(String checkId);

	public Response<Void> agentCheckDeregister(String checkId, String token);

	public Response<Void> agentCheckPass(String checkId);

	public Response<Void> agentCheckPass(String checkId, String note);

	public Response<Void> agentCheckPass(String checkId, String note, String token);

	public Response<Void> agentCheckWarn(String checkId);

	public Response<Void> agentCheckWarn(String checkId, String note);

	public Response<Void> agentCheckWarn(String checkId, String note, String token);

	public Response<Void> agentCheckFail(String checkId);

	public Response<Void> agentCheckFail(String checkId, String note);

	public Response<Void> agentCheckFail(String checkId, String note, String token);

	public Response<Void> agentServiceRegister(NewService newService);

	public Response<Void> agentServiceRegister(NewService newService, String token);

	public Response<Void> agentServiceDeregister(String serviceId);

	public Response<Void> agentServiceDeregister(String serviceId, String token);

	public Response<Void> agentServiceSetMaintenance(String serviceId, boolean maintenanceEnabled);

	public Response<Void> agentServiceSetMaintenance(String serviceId, boolean maintenanceEnabled, String reason);

	public Response<Void> agentReload();
} public final class AgentConsulClient implements AgentClient {

	private final ConsulRawClient rawClient;

	public AgentConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public AgentConsulClient() {
		this(new ConsulRawClient());
	}

	public AgentConsulClient(TLSConfig tlsConfig) {
		this(new ConsulRawClient(tlsConfig));
	}

	public AgentConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public AgentConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public AgentConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	public AgentConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<Map<String, Check>> getAgentChecks() {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/agent/checks");

		if (httpResponse.getStatusCode() == 200) {
			Map<String, Check> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<Map<String, Check>>() {
			}.getType());
			return new Response<Map<String, Check>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Map<String, Service>> getAgentServices() {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/agent/services");

		if (httpResponse.getStatusCode() == 200) {
			Map<String, Service> agentServices = GsonFactory.getGson().fromJson(httpResponse.getContent(),
					new TypeToken<Map<String, Service>>() {
					}.getType());
			return new Response<Map<String, Service>>(agentServices, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Member>> getAgentMembers() {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/agent/members");

		if (httpResponse.getStatusCode() == 200) {
			List<Member> members = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Member>>() {
			}.getType());
			return new Response<List<Member>>(members, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Self> getAgentSelf() {
		return getAgentSelf(null);
	}

	@Override
	public Response<Self> getAgentSelf(String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;

		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/agent/self", tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			Self self = GsonFactory.getGson().fromJson(httpResponse.getContent(), Self.class);
			return new Response<Self>(self, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentSetMaintenance(boolean maintenanceEnabled) {
		return agentSetMaintenance(maintenanceEnabled, null);
	}

	@Override
	public Response<Void> agentSetMaintenance(boolean maintenanceEnabled, String reason) {
		UrlParameters maintenanceParameter = new SingleUrlParameters("enable", Boolean.toString(maintenanceEnabled));
		UrlParameters reasonParamenter = reason != null ? new SingleUrlParameters("reason", reason) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/maintenance", "", maintenanceParameter, reasonParamenter);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}

	}

	@Override
	public Response<Void> agentJoin(String address, boolean wan) {
		UrlParameters wanParams = wan ? new SingleUrlParameters("wan", "1") : null;
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/join/" + address, "", wanParams);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentForceLeave(String node) {
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/force-leave/" + node, "");

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentCheckRegister(NewCheck newCheck) {
		return agentCheckRegister(newCheck, null);
	}

	@Override
	public Response<Void> agentCheckRegister(NewCheck newCheck, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;

		String json = GsonFactory.getGson().toJson(newCheck);
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/check/register", json, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentCheckDeregister(String checkId) {
		return agentCheckDeregister(checkId, null);
	}

	@Override
	public Response<Void> agentCheckDeregister(String checkId, String token) {
		UrlParameters tokenParameter = token != null ? new SingleUrlParameters("token", token) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/check/deregister/" + checkId, "", tokenParameter);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentCheckPass(String checkId) {
		return agentCheckPass(checkId, null);
	}

	@Override
	public Response<Void> agentCheckPass(String checkId, String note) {
		return agentCheckPass(checkId, note, null);
	}

	@Override
	public Response<Void> agentCheckPass(String checkId, String note, String token) {
		UrlParameters noteParameter = note != null ? new SingleUrlParameters("note", note) : null;
		UrlParameters tokenParameter = token != null ? new SingleUrlParameters("token", token) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/check/pass/" + checkId, "", noteParameter, tokenParameter);
    
		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentCheckWarn(String checkId) {
		return agentCheckWarn(checkId, null);
	}

	@Override
	public Response<Void> agentCheckWarn(String checkId, String note) {
		return agentCheckWarn(checkId, note, null);
	}

	@Override
	public Response<Void> agentCheckWarn(String checkId, String note, String token) {
		UrlParameters noteParameter = note != null ? new SingleUrlParameters("note", note) : null;
		UrlParameters tokenParameter = token != null ? new SingleUrlParameters("token", token) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/check/warn/" + checkId, "", noteParameter, tokenParameter);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentCheckFail(String checkId) {
		return agentCheckFail(checkId, null);
	}

	@Override
	public Response<Void> agentCheckFail(String checkId, String note) {
		return agentCheckFail(checkId, note, null);
	}

	@Override
	public Response<Void> agentCheckFail(String checkId, String note, String token) {
		UrlParameters noteParameter = note != null ? new SingleUrlParameters("note", note) : null;
		UrlParameters tokenParameter = token != null ? new SingleUrlParameters("token", token) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/check/fail/" + checkId, "", noteParameter, tokenParameter);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentServiceRegister(NewService newService) {
		return agentServiceRegister(newService, null);
	}

	@Override
	public Response<Void> agentServiceRegister(NewService newService, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;

		String json = GsonFactory.getGson().toJson(newService);
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/service/register", json, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentServiceDeregister(String serviceId) {
		return agentServiceDeregister(serviceId, null);
	}

	@Override
	public Response<Void> agentServiceDeregister(String serviceId, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/service/deregister/" + serviceId, "", tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentServiceSetMaintenance(String serviceId, boolean maintenanceEnabled) {
		return agentServiceSetMaintenance(serviceId, maintenanceEnabled, null);
	}

	@Override
	public Response<Void> agentServiceSetMaintenance(String serviceId, boolean maintenanceEnabled, String reason) {
		UrlParameters maintenanceParameter = new SingleUrlParameters("enable", Boolean.toString(maintenanceEnabled));
		UrlParameters reasonParameter = reason != null ? new SingleUrlParameters("reason", reason) : null;

		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/service/maintenance/" + serviceId, "", maintenanceParameter, reasonParameter);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> agentReload() {
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/agent/reload", "");

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}

	}
} public interface CoordinateClient {

	public Response<List<Datacenter>> getDatacenters();

	public Response<List<Node>> getNodes(QueryParams queryParams);

} public class CoordinateConsulClient implements CoordinateClient {

	private final ConsulRawClient rawClient;

	public CoordinateConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	@Override
	public Response<List<Datacenter>> getDatacenters() {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/coordinate/datacenters");

		if (httpResponse.getStatusCode() == 200) {
			List<Datacenter> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Datacenter>>() {
			}.getType());
			return new Response<List<Datacenter>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Node>> getNodes(QueryParams queryParams) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/coordinate/nodes", queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<Node> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Node>>() {
			}.getType());
			return new Response<List<Node>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}
} public class Datacenter {

	@SerializedName("Datacenter")
	private String datacenter;

	@SerializedName("AreaID")
	private String areaId;

	@SerializedName("Coordinates")
	private List<Node> coordinates;

	public String getDatacenter() {
		return datacenter;
	}

	public void setDatacenter(String datacenter) {
		this.datacenter = datacenter;
	}

	public String getAreaId() {
		return areaId;
	}

	public void setAreaId(String areaId) {
		this.areaId = areaId;
	}

	public List<Node> getCoordinates() {
		return coordinates;
	}

	public void setCoordinates(List<Node> coordinates) {
		this.coordinates = coordinates;
	}

	@Override
	public String toString() {
		return "Datacenter{" +
				"datacenter='" + datacenter + '\'' +
				", areaId='" + areaId + '\'' +
				", coordinates=" + coordinates +
				'}';
	}
} public interface EventClient {

	public Response<Event> eventFire(String event, String payload, EventParams eventParams, QueryParams queryParams);

	// -------------------------------------------------------------------------------

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #eventList(EventListRequest eventListRequest)}
	 */
	@Deprecated
	public Response<List<Event>> eventList(QueryParams queryParams);

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #eventList(EventListRequest eventListRequest)}
	 */
	@Deprecated
	public Response<List<Event>> eventList(String event, QueryParams queryParams);

	public Response<List<Event>> eventList(EventListRequest eventListRequest);

} public final class EventConsulClient implements EventClient {

	private final ConsulRawClient rawClient;

	public EventConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public EventConsulClient() {
		this(new ConsulRawClient());
	}

	public EventConsulClient(TLSConfig tlsConfig) {
		this(new ConsulRawClient(tlsConfig));
	}

	public EventConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public EventConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public EventConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<Event> eventFire(String event, String payload, EventParams eventParams, QueryParams queryParams) {
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/event/fire/" + event, payload, eventParams, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			Event value = GsonFactory.getGson().fromJson(httpResponse.getContent(), Event.class);
			return new Response<Event>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Event>> eventList(QueryParams queryParams) {
		return eventList(null, queryParams);
	}

	@Override
	public Response<List<Event>> eventList(String event, QueryParams queryParams) {
		EventListRequest request = EventListRequest.newBuilder()
				.setName(event)
				.setQueryParams(queryParams)
				.build();

		return eventList(request);
	}

	@Override
	public Response<List<Event>> eventList(EventListRequest eventListRequest) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/event/list", eventListRequest.asUrlParameters());

		if (httpResponse.getStatusCode() == 200) {
			List<Event> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Event>>() {
			}.getType());
			return new Response<List<Event>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}
} public final class EventListRequest implements ConsulRequest {

	private final String name;
	private final String node;
	private final String service;
	private final String tag;
	private final QueryParams queryParams;
	private final String token;

	private EventListRequest(String name, String node, String service, String tag, QueryParams queryParams, String token) {
		this.name = name;
		this.node = node;
		this.service = service;
		this.tag = tag;
		this.queryParams = queryParams;
		this.token = token;
	}

	public String getName() {
		return name;
	}

	public String getNode() {
		return node;
	}

	public String getService() {
		return service;
	}

	public String getTag() {
		return tag;
	}

	public QueryParams getQueryParams() {
		return queryParams;
	}

	public String getToken() {
		return token;
	}

	public static class Builder {
		private String name;
		private String node;
		private String service;
		private String tag;
		private QueryParams queryParams;
		private String token;

		public Builder setName(String name) {
			this.name = name;
			return this;
		}

		public Builder setNode(String node) {
			this.node = node;
			return this;
		}

		public Builder setService(String service) {
			this.service = service;
			return this;
		}

		public Builder setTag(String tag) {
			this.tag = tag;
			return this;
		}

		public Builder setQueryParams(QueryParams queryParams) {
			this.queryParams = queryParams;
			return this;
		}

		public Builder setToken(String token) {
			this.token = token;
			return this;
		}

		public EventListRequest build() {
			return new EventListRequest(name, node, service, tag, queryParams, token);
		}
	}

	public static Builder newBuilder() {
		return new Builder();
	}

	@Override
	public List<UrlParameters> asUrlParameters() {
		List<UrlParameters> params = new ArrayList<>();

		if (name != null) {
			params.add(new SingleUrlParameters("name", name));
		}

		if (node != null) {
			params.add(new SingleUrlParameters("node", node));
		}

		if (service != null) {
			params.add(new SingleUrlParameters("service", service));
		}

		if (tag != null) {
			params.add(new SingleUrlParameters("tag", tag));
		}

		if (queryParams != null) {
			params.add(queryParams);
		}

		if (token != null) {
			params.add(new SingleUrlParameters("token", token));
		}

		return params;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (!(o instanceof EventListRequest)) {
			return false;
		}
		EventListRequest that = (EventListRequest) o;
		return Objects.equals(name, that.name) &&
			Objects.equals(node, that.node) &&
			Objects.equals(service, that.service) &&
			Objects.equals(tag, that.tag) &&
			Objects.equals(queryParams, that.queryParams) &&
			Objects.equals(token, that.token);
	}

	@Override
	public int hashCode() {
		return Objects.hash(name, node, service, tag, queryParams, token);
	}
} public class EventParams implements UrlParameters {

	private String name;
	private String service;
	private String tag;
	private String node;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getService() {
		return service;
	}

	public void setService(String service) {
		this.service = service;
	}

	public String getTag() {
		return tag;
	}

	public void setTag(String tag) {
		this.tag = tag;
	}

	public String getNode() {
		return node;
	}

	public void setNode(String node) {
		this.node = node;
	}

	@Override
	public List<String> toUrlParameters() {
		List<String> result = new ArrayList<String>();

		if (name != null) {
			result.add("name=" + Utils.encodeValue(name));
		}

		if (service != null) {
			result.add("service=" + Utils.encodeValue(service));
		}

		if (tag != null) {
			result.add("tag=" + Utils.encodeValue(tag));
		}

		if (node != null) {
			result.add("node=" + Utils.encodeValue(node));
		}

		return result;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (!(o instanceof EventParams)) {
			return false;
		}
		EventParams that = (EventParams) o;
		return Objects.equals(name, that.name) &&
			Objects.equals(service, that.service) &&
			Objects.equals(tag, that.tag) &&
			Objects.equals(node, that.node);
	}

	@Override
	public int hashCode() {
		return Objects.hash(name, service, tag, node);
	}
} public final class HealthChecksForServiceRequest implements ConsulRequest {

	private final String datacenter;
	private final String near;
	private final Map<String, String> nodeMeta;
	private final QueryParams queryParams;

	public HealthChecksForServiceRequest(String datacenter, String near, Map<String, String> nodeMeta, QueryParams queryParams) {
		this.datacenter = datacenter;
		this.near = near;
		this.nodeMeta = nodeMeta;
		this.queryParams = queryParams;
	}

	public String getDatacenter() {
		return datacenter;
	}

	public String getNear() {
		return near;
	}

	public Map<String, String> getNodeMeta() {
		return nodeMeta;
	}

	public QueryParams getQueryParams() {
		return queryParams;
	}

	public static class Builder {
		private String datacenter;
		private String near;
		private Map<String, String> nodeMeta;
		private QueryParams queryParams;

		private Builder() {
		}

		public Builder setDatacenter(String datacenter) {
			this.datacenter = datacenter;
			return this;
		}

		public Builder setNear(String near) {
			this.near = near;
			return this;
		}

		public Builder setNodeMeta(Map<String, String> nodeMeta) {
			this.nodeMeta = nodeMeta != null ? Collections.unmodifiableMap(nodeMeta) : null;
			return this;
		}

		public Builder setQueryParams(QueryParams queryParams) {
			this.queryParams = queryParams;
			return this;
		}

		public HealthChecksForServiceRequest build() {
			return new HealthChecksForServiceRequest(datacenter, near, nodeMeta, queryParams);
		}
	}

	public static Builder newBuilder() {
		return new Builder();
	}

	@Override
	public List<UrlParameters> asUrlParameters() {
		List<UrlParameters> params = new ArrayList<>();

		if (datacenter != null) {
			params.add(new SingleUrlParameters("dc", datacenter));
		}

		if (near != null) {
			params.add(new SingleUrlParameters("near", near));
		}

		if (nodeMeta != null) {
			params.add(new NodeMetaParameters(nodeMeta));
		}

		if (queryParams != null) {
			params.add(queryParams);
		}

		return params;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (!(o instanceof HealthChecksForServiceRequest)) {
			return false;
		}
		HealthChecksForServiceRequest that = (HealthChecksForServiceRequest) o;
		return Objects.equals(datacenter, that.datacenter) &&
			Objects.equals(near, that.near) &&
			Objects.equals(nodeMeta, that.nodeMeta) &&
			Objects.equals(queryParams, that.queryParams);
	}

	@Override
	public int hashCode() {
		return Objects.hash(datacenter, near, nodeMeta, queryParams);
	}
} public interface HealthClient {

	public Response<List<Check>> getHealthChecksForNode(String nodeName, QueryParams queryParams);

	// -------------------------------------------------------------------------------

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #getHealthChecksForService(String serviceName, HealthChecksForServiceRequest healthChecksForServiceRequest)}
	 */
	@Deprecated
	public Response<List<Check>> getHealthChecksForService(String serviceName, QueryParams queryParams);

	public Response<List<Check>> getHealthChecksForService(String serviceName, HealthChecksForServiceRequest healthChecksForServiceRequest);

	// -------------------------------------------------------------------------------

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest)}
	 */
	@Deprecated
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, boolean onlyPassing, QueryParams queryParams);

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest)}
	 */
	@Deprecated
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, String tag, boolean onlyPassing, QueryParams queryParams);

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest)}
	 */
	@Deprecated
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, boolean onlyPassing, QueryParams queryParams, String token);

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest)}
	 */
	@Deprecated
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, String tag, boolean onlyPassing, QueryParams queryParams, String token);

	/**
	 * @deprecated This method will be removed in consul-api 2.0. Use {@link #getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest)}
	 */
	@Deprecated
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, String[] tags, boolean onlyPassing, QueryParams queryParams, String token);

	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest);

	// -------------------------------------------------------------------------------

	public Response<List<Check>> getHealthChecksState(QueryParams queryParams);

	public Response<List<Check>> getHealthChecksState(Check.CheckStatus checkStatus, QueryParams queryParams);
} public final class HealthConsulClient implements HealthClient {

	private final ConsulRawClient rawClient;

	public HealthConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public HealthConsulClient() {
		this(new ConsulRawClient());
	}

	public HealthConsulClient(TLSConfig tlsConfig) {
		this(new ConsulRawClient(tlsConfig));
	}

	public HealthConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public HealthConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public HealthConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	public HealthConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<List<Check>> getHealthChecksForNode(String nodeName, QueryParams queryParams) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/health/node/" + nodeName, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<Check> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Check>>() {
			}.getType());
			return new Response<List<Check>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Check>> getHealthChecksForService(String serviceName, QueryParams queryParams) {
		HealthChecksForServiceRequest request = HealthChecksForServiceRequest.newBuilder()
				.setQueryParams(queryParams)
				.build();

		return getHealthChecksForService(serviceName, request);
	}

	@Override
	public Response<List<Check>> getHealthChecksForService(String serviceName, HealthChecksForServiceRequest healthChecksForServiceRequest) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/health/checks/" + serviceName, healthChecksForServiceRequest.asUrlParameters());

		if (httpResponse.getStatusCode() == 200) {
			List<Check> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Check>>() {
			}.getType());
			return new Response<List<Check>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, boolean onlyPassing, QueryParams queryParams) {
		return getHealthServices(serviceName, (String) null, onlyPassing, queryParams, null);
	}

	@Override
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, boolean onlyPassing, QueryParams queryParams, String token) {
		return getHealthServices(serviceName, (String) null, onlyPassing, queryParams, token);
	}

	@Override
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, String tag, boolean onlyPassing, QueryParams queryParams) {
		return getHealthServices(serviceName, tag, onlyPassing, queryParams, null);
	}

	@Override
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, String tag, boolean onlyPassing, QueryParams queryParams, String token) {
		return getHealthServices(serviceName, new String[]{tag}, onlyPassing, queryParams, token);
	}

	@Override
	public Response<List<com.ecwid.consul.v1.health.model.HealthService>> getHealthServices(String serviceName, String[] tags, boolean onlyPassing, QueryParams queryParams, String token) {
		HealthServicesRequest request = HealthServicesRequest.newBuilder()
				.setTags(tags)
				.setPassing(onlyPassing)
				.setQueryParams(queryParams)
				.setToken(token)
				.build();

		return getHealthServices(serviceName, request);
	}

	@Override
	public Response<List<HealthService>> getHealthServices(String serviceName, HealthServicesRequest healthServicesRequest) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/health/service/" + serviceName, healthServicesRequest.asUrlParameters());

		if (httpResponse.getStatusCode() == 200) {
			List<com.ecwid.consul.v1.health.model.HealthService> value = GsonFactory.getGson().fromJson(httpResponse.getContent(),
					new TypeToken<List<com.ecwid.consul.v1.health.model.HealthService>>() {
					}.getType());
			return new Response<List<com.ecwid.consul.v1.health.model.HealthService>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Check>> getHealthChecksState(QueryParams queryParams) {
		return getHealthChecksState(null, queryParams);
	}

	@Override
	public Response<List<Check>> getHealthChecksState(Check.CheckStatus checkStatus, QueryParams queryParams) {
		String status = checkStatus == null ? "any" : checkStatus.name().toLowerCase();
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/health/state/" + status, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<Check> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Check>>() {
			}.getType());
			return new Response<List<Check>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

} public final class HealthServicesRequest implements ConsulRequest {

	private final String datacenter;
	private final String near;
	private final String[] tags;
	private final Map<String, String> nodeMeta;
	private final boolean passing;
	private final QueryParams queryParams;
	private final String token;

	private HealthServicesRequest(String datacenter, String near, String[] tags, Map<String, String> nodeMeta, boolean passing, QueryParams queryParams, String token) {
		this.datacenter = datacenter;
		this.near = near;
		this.tags = tags;
		this.nodeMeta = nodeMeta;
		this.passing = passing;
		this.queryParams = queryParams;
		this.token = token;
	}

	public String getDatacenter() {
		return datacenter;
	}

	public String getNear() {
		return near;
	}

	public String getTag() {
		return tags != null && tags.length > 0 ? tags[0] : null;
	}

	public String[] getTags() {
		return tags;
	}

	public Map<String, String> getNodeMeta() {
		return nodeMeta;
	}

	public boolean isPassing() {
		return passing;
	}

	public QueryParams getQueryParams() {
		return queryParams;
	}

	public String getToken() {
		return token;
	}

	public static class Builder {
		private String datacenter;
		private String near;
		private String[] tags;
		private Map<String, String> nodeMeta;
		private boolean passing;
		private QueryParams queryParams;
		private String token;

		private Builder() {
		}

		public Builder setDatacenter(String datacenter) {
			this.datacenter = datacenter;
			return this;
		}

		public Builder setNear(String near) {
			this.near = near;
			return this;
		}

		public Builder setTag(String tag) {
			this.tags = new String[]{tag};
			return this;
		}

		public Builder setTags(String[] tags) {
			this.tags = tags;
			return this;
		}

		public Builder setNodeMeta(Map<String, String> nodeMeta) {
			this.nodeMeta = nodeMeta != null ? Collections.unmodifiableMap(nodeMeta) : null;
			return this;
		}

		public Builder setPassing(boolean passing) {
			this.passing = passing;
			return this;
		}

		public Builder setQueryParams(QueryParams queryParams) {
			this.queryParams = queryParams;
			return this;
		}

		public Builder setToken(String token) {
			this.token = token;
			return this;
		}

		public HealthServicesRequest build() {
			return new HealthServicesRequest(datacenter, near, tags, nodeMeta, passing, queryParams, token);
		}
	}

	public static Builder newBuilder() {
		return new Builder();
	}

	@Override
	public List<UrlParameters> asUrlParameters() {
		List<UrlParameters> params = new ArrayList<>();

		if (datacenter != null) {
			params.add(new SingleUrlParameters("dc", datacenter));
		}

		if (near != null) {
			params.add(new SingleUrlParameters("near", near));
		}

		if (tags != null) {
			params.add(new TagsParameters(tags));
		}

		if (nodeMeta != null) {
			params.add(new NodeMetaParameters(nodeMeta));
		}

		params.add(new SingleUrlParameters("passing", String.valueOf(passing)));

		if (queryParams != null) {
			params.add(queryParams);
		}

		if (token != null) {
			params.add(new SingleUrlParameters("token", token));
		}

		return params;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (!(o instanceof HealthServicesRequest)) {
			return false;
		}
		HealthServicesRequest that = (HealthServicesRequest) o;
		return passing == that.passing &&
			Objects.equals(datacenter, that.datacenter) &&
			Objects.equals(near, that.near) &&
			Arrays.equals(tags, that.tags) &&
			Objects.equals(nodeMeta, that.nodeMeta) &&
			Objects.equals(queryParams, that.queryParams) &&
			Objects.equals(token, that.token);
	}

	@Override
	public int hashCode() {
		int result = Objects.hash(datacenter, near, nodeMeta, passing, queryParams, token);
		result = 31 * result + Arrays.hashCode(tags);
		return result;
	}
} public class HealthService {

    public static class Node {

        @SerializedName("ID")
        private String id;

        @SerializedName("Node")
        private String node;

        @SerializedName("Address")
        private String address;

        @SerializedName("Datacenter")
        private String datacenter;

        @SerializedName("TaggedAddresses")
        private Map<String, String> taggedAddresses;

        @SerializedName("Meta")
        private Map<String, String> meta;

        @SerializedName("CreateIndex")
        private Long createIndex;

        @SerializedName("ModifyIndex")
        private Long modifyIndex;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getNode() {
            return node;
        }

        public void setNode(String node) {
            this.node = node;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getDatacenter() {
            return datacenter;
        }

        public void setDatacenter(String datacenter) {
            this.datacenter = datacenter;
        }

        public Map<String, String> getTaggedAddresses() {
            return taggedAddresses;
        }

        public void setTaggedAddresses(Map<String, String> taggedAddresses) {
            this.taggedAddresses = taggedAddresses;
        }

        public Map<String, String> getMeta() {
            return meta;
        }

        public void setMeta(Map<String, String> meta) {
            this.meta = meta;
        }

        public Long getCreateIndex() {
            return createIndex;
        }

        public void setCreateIndex(Long createIndex) {
            this.createIndex = createIndex;
        }

        public Long getModifyIndex() {
            return modifyIndex;
        }

        public void setModifyIndex(Long modifyIndex) {
            this.modifyIndex = modifyIndex;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "id='" + id + '\'' +
                    ", node='" + node + '\'' +
                    ", address='" + address + '\'' +
                    ", datacenter='" + datacenter + '\'' +
                    ", taggedAddresses=" + taggedAddresses +
                    ", meta=" + meta +
                    ", createIndex=" + createIndex +
                    ", modifyIndex=" + modifyIndex +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Node node1 = (Node) o;
            return Objects.equals(id, node1.id) &&
                    Objects.equals(node, node1.node) &&
                    Objects.equals(address, node1.address) &&
                    Objects.equals(datacenter, node1.datacenter) &&
                    Objects.equals(taggedAddresses, node1.taggedAddresses) &&
                    Objects.equals(meta, node1.meta) &&
                    Objects.equals(createIndex, node1.createIndex) &&
                    Objects.equals(modifyIndex, node1.modifyIndex);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, node, address, datacenter, taggedAddresses, meta, createIndex, modifyIndex);
        }
    }

    public static class Service {
        @SerializedName("ID")
        private String id;

        @SerializedName("Service")
        private String service;

        @SerializedName("Tags")
        private List<String> tags;

        @SerializedName("Address")
        private String address;

        @SerializedName("Meta")
        private Map<String, String> meta;

        @SerializedName("Port")
        private Integer port;

        @SerializedName("EnableTagOverride")
        private Boolean enableTagOverride;

        @SerializedName("CreateIndex")
        private Long createIndex;

        @SerializedName("ModifyIndex")
        private Long modifyIndex;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getService() {
            return service;
        }

        public void setService(String service) {
            this.service = service;
        }

        public List<String> getTags() {
            return tags;
        }

        public void setTags(List<String> tags) {
            this.tags = tags;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public Map<String, String> getMeta() {
            return meta;
        }

        public void setMeta(Map<String, String> meta) {
            this.meta = meta;
        }

        public Integer getPort() {
            return port;
        }

        public void setPort(Integer port) {
            this.port = port;
        }

        public Boolean getEnableTagOverride() {
            return enableTagOverride;
        }

        public void setEnableTagOverride(Boolean enableTagOverride) {
            this.enableTagOverride = enableTagOverride;
        }

        public Long getCreateIndex() {
            return createIndex;
        }

        public void setCreateIndex(Long createIndex) {
            this.createIndex = createIndex;
        }

        public Long getModifyIndex() {
            return modifyIndex;
        }

        public void setModifyIndex(Long modifyIndex) {
            this.modifyIndex = modifyIndex;
        }

        @Override
        public String toString() {
            return "Service{" +
                    "id='" + id + '\'' +
                    ", service='" + service + '\'' +
                    ", tags=" + tags +
                    ", address='" + address + '\'' +
                    ", meta=" + meta +
                    ", port=" + port +
                    ", enableTagOverride=" + enableTagOverride +
                    ", createIndex=" + createIndex +
                    ", modifyIndex=" + modifyIndex +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Service service1 = (Service) o;
            return Objects.equals(id, service1.id) &&
                    Objects.equals(service, service1.service) &&
                    Objects.equals(tags, service1.tags) &&
                    Objects.equals(address, service1.address) &&
                    Objects.equals(meta, service1.meta) &&
                    Objects.equals(port, service1.port) &&
                    Objects.equals(enableTagOverride, service1.enableTagOverride) &&
                    Objects.equals(createIndex, service1.createIndex) &&
                    Objects.equals(modifyIndex, service1.modifyIndex);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, service, tags, address, meta, port, enableTagOverride, createIndex, modifyIndex);
        }
    }

    @SerializedName("Node")
    private Node node;

    @SerializedName("Service")
    private Service service;

    @SerializedName("Checks")
    private List<Check> checks;

    public Node getNode() {
        return node;
    }

    public void setNode(Node node) {
        this.node = node;
    }

    public Service getService() {
        return service;
    }

    public void setService(Service service) {
        this.service = service;
    }

    public List<Check> getChecks() {
        return checks;
    }

    public void setChecks(List<Check> checks) {
        this.checks = checks;
    }

    @Override
    public String toString() {
        return "HealthService{" +
                "node=" + node +
                ", service=" + service +
                ", checks=" + checks +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        HealthService that = (HealthService) o;
        return Objects.equals(node, that.node) &&
                Objects.equals(service, that.service) &&
                Objects.equals(checks, that.checks);
    }

    @Override
    public int hashCode() {
        return Objects.hash(node, service, checks);
    }
} public final class KeyValueConsulClient implements KeyValueClient {

	private final ConsulRawClient rawClient;

	public KeyValueConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public KeyValueConsulClient() {
		this(new ConsulRawClient());
	}

	public KeyValueConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public KeyValueConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	public KeyValueConsulClient(TLSConfig tlsConfig) {
		this(new ConsulRawClient(tlsConfig));
	}

	public KeyValueConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public KeyValueConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<GetValue> getKVValue(String key) {
		return getKVValue(key, QueryParams.DEFAULT);
	}

	@Override
	public Response<GetValue> getKVValue(String key, String token) {
		return getKVValue(key, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<GetValue> getKVValue(String key, QueryParams queryParams) {
		return getKVValue(key, null, queryParams);
	}

	@Override
	public Response<GetValue> getKVValue(String key, String token, QueryParams queryParams) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/kv/" + key, tokenParams, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<GetValue> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<GetValue>>() {
			}.getType());

			if (value.size() == 0) {
				return new Response<GetValue>(null, httpResponse);
			} else if (value.size() == 1) {
				return new Response<GetValue>(value.get(0), httpResponse);
			} else {
				throw new ConsulException("Strange response (list size=" + value.size() + ")");
			}
		} else if (httpResponse.getStatusCode() == 404) {
			return new Response<GetValue>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<GetBinaryValue> getKVBinaryValue(String key) {
		return getKVBinaryValue(key, QueryParams.DEFAULT);
	}

	@Override
	public Response<GetBinaryValue> getKVBinaryValue(String key, String token) {
		return getKVBinaryValue(key, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<GetBinaryValue> getKVBinaryValue(String key, QueryParams queryParams) {
		return getKVBinaryValue(key, null, queryParams);
	}

	@Override
	public Response<GetBinaryValue> getKVBinaryValue(String key, String token, QueryParams queryParams) {
		UrlParameters tokenParams = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/kv/" + key, tokenParams, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<GetBinaryValue> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<GetBinaryValue>>() {
			}.getType());

			if (value.size() == 0) {
				return new Response<GetBinaryValue>(null, httpResponse);
			} else if (value.size() == 1) {
				return new Response<GetBinaryValue>(value.get(0), httpResponse);
			} else {
				throw new ConsulException("Strange response (list size=" + value.size() + ")");
			}
		} else if (httpResponse.getStatusCode() == 404) {
			return new Response<GetBinaryValue>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<GetValue>> getKVValues(String keyPrefix) {
		return getKVValues(keyPrefix, QueryParams.DEFAULT);
	}

	@Override
	public Response<List<GetValue>> getKVValues(String keyPrefix, String token) {
		return getKVValues(keyPrefix, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<List<GetValue>> getKVValues(String keyPrefix, QueryParams queryParams) {
		return getKVValues(keyPrefix, null, queryParams);
	}

	@Override
	public Response<List<GetValue>> getKVValues(String keyPrefix, String token, QueryParams queryParams) {
		UrlParameters recurseParam = new SingleUrlParameters("recurse");
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/kv/" + keyPrefix, recurseParam, tokenParam, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<GetValue> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<GetValue>>() {
			}.getType());
			return new Response<List<GetValue>>(value, httpResponse);
		} else if (httpResponse.getStatusCode() == 404) {
			return new Response<List<GetValue>>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<GetBinaryValue>> getKVBinaryValues(String keyPrefix) {
		return getKVBinaryValues(keyPrefix, QueryParams.DEFAULT);
	}

	@Override
	public Response<List<GetBinaryValue>> getKVBinaryValues(String keyPrefix, String token) {
		return getKVBinaryValues(keyPrefix, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<List<GetBinaryValue>> getKVBinaryValues(String keyPrefix, QueryParams queryParams) {
		return getKVBinaryValues(keyPrefix, null, queryParams);
	}

	@Override
	public Response<List<GetBinaryValue>> getKVBinaryValues(String keyPrefix, String token, QueryParams queryParams) {
		UrlParameters recurseParam = new SingleUrlParameters("recurse");
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/kv/" + keyPrefix, recurseParam, tokenParam, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<GetBinaryValue> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<GetBinaryValue>>() {
			}.getType());
			return new Response<List<GetBinaryValue>>(value, httpResponse);
		} else if (httpResponse.getStatusCode() == 404) {
			return new Response<List<GetBinaryValue>>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<String>> getKVKeysOnly(String keyPrefix) {
		return getKVKeysOnly(keyPrefix, QueryParams.DEFAULT);
	}

	@Override
	public Response<List<String>> getKVKeysOnly(String keyPrefix, String separator, String token) {
		return getKVKeysOnly(keyPrefix, separator, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<List<String>> getKVKeysOnly(String keyPrefix, QueryParams queryParams) {
		return getKVKeysOnly(keyPrefix, null, null, queryParams);
	}

	@Override
	public Response<List<String>> getKVKeysOnly(String keyPrefix, String separator, String token, QueryParams queryParams) {
		UrlParameters keysParam = new SingleUrlParameters("keys");
		UrlParameters separatorParam = separator != null ? new SingleUrlParameters("separator", separator) : null;
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/kv/" + keyPrefix, keysParam, separatorParam, tokenParam, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			List<String> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<String>>() {
			}.getType());
			return new Response<List<String>>(value, httpResponse);
		} else if (httpResponse.getStatusCode() == 404) {
			return new Response<List<String>>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Boolean> setKVValue(String key, String value) {
		return setKVValue(key, value, QueryParams.DEFAULT);
	}

	@Override
	public Response<Boolean> setKVValue(String key, String value, PutParams putParams) {
		return setKVValue(key, value, putParams, QueryParams.DEFAULT);
	}

	@Override
	public Response<Boolean> setKVValue(String key, String value, String token, PutParams putParams) {
		return setKVValue(key, value, token, putParams, QueryParams.DEFAULT);
	}

	@Override
	public Response<Boolean> setKVValue(String key, String value, QueryParams queryParams) {
		return setKVValue(key, value, null, null, queryParams);
	}

	@Override
	public Response<Boolean> setKVValue(String key, String value, PutParams putParams, QueryParams queryParams) {
		return setKVValue(key, value, null, putParams, queryParams);
	}

	@Override
	public Response<Boolean> setKVValue(String key, String value, String token, PutParams putParams, QueryParams queryParams) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/kv/" + key, value, putParams, tokenParam, queryParams);

		if (httpResponse.getStatusCode() == 200) {
			boolean result = GsonFactory.getGson().fromJson(httpResponse.getContent(), boolean.class);
			return new Response<Boolean>(result, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Boolean> setKVBinaryValue(String key, byte[] value) {
		return setKVBinaryValue(key, value, QueryParams.DEFAULT);
	}

	@Override
	public Response<Boolean> setKVBinaryValue(String key, byte[] value, PutParams putParams) {
		return setKVBinaryValue(key, value, putParams, QueryParams.DEFAULT);
	}

	@Override
	public Response<Boolean> setKVBinaryValue(String key, byte[] value, String token, PutParams putParams) {
		return setKVBinaryValue(key, value, token, putParams, QueryParams.DEFAULT);
	}

	@Override
	public Response<Boolean> setKVBinaryValue(String key, byte[] value, QueryParams queryParams) {
		return setKVBinaryValue(key, value, null, null, queryParams);
	}

	@Override
	public Response<Boolean> setKVBinaryValue(String key, byte[] value, PutParams putParams, QueryParams queryParams) {
		return setKVBinaryValue(key, value, null, putParams, queryParams);
	}

	@Override
	public Response<Boolean> setKVBinaryValue(String key, byte[] value, String token, PutParams putParams, QueryParams queryParams) {
		Request request = Request.Builder.newBuilder()
			.setEndpoint("/v1/kv/" + key)
			.setToken(token)
			.addUrlParameter(queryParams)
			.addUrlParameter(putParams)
			.setBinaryContent(value)
			.build();

		HttpResponse httpResponse = rawClient.makePutRequest(request);

		if (httpResponse.getStatusCode() == 200) {
			boolean result = GsonFactory.getGson().fromJson(httpResponse.getContent(), boolean.class);
			return new Response<Boolean>(result, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> deleteKVValue(String key) {
		return deleteKVValue(key, QueryParams.DEFAULT);
	}

	@Override
	public Response<Void> deleteKVValue(String key, String token) {
		return deleteKVValue(key, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<Void> deleteKVValue(String key, QueryParams queryParams) {
		return deleteKVValue(key, null, queryParams);
	}

	@Override
	public Response<Void> deleteKVValue(String key, String token, QueryParams queryParams) {
		Request request = Request.Builder.newBuilder()
			.setEndpoint("/v1/kv/" + key)
			.setToken(token)
			.addUrlParameter(queryParams)
			.build();

		HttpResponse httpResponse = rawClient.makeDeleteRequest(request);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> deleteKVValues(String key) {
		return deleteKVValues(key, QueryParams.DEFAULT);
	}

	@Override
	public Response<Void> deleteKVValues(String key, String token) {
		return deleteKVValues(key, token, QueryParams.DEFAULT);
	}

	@Override
	public Response<Void> deleteKVValues(String key, QueryParams queryParams) {
		return deleteKVValues(key, null, queryParams);
	}

	@Override
	public Response<Void> deleteKVValues(String key, String token, QueryParams queryParams) {
		UrlParameters recurseParam = new SingleUrlParameters("recurse");

		Request request = Request.Builder.newBuilder()
			.setEndpoint("/v1/kv/" + key)
			.setToken(token)
			.addUrlParameter(recurseParam)
			.addUrlParameter(queryParams)
			.build();

		HttpResponse httpResponse = rawClient.makeDeleteRequest(request);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}
} public class GetBinaryValue {

	@SerializedName("CreateIndex")
	private long createIndex;

	@SerializedName("ModifyIndex")
	private long modifyIndex;

	@SerializedName("LockIndex")
	private Long lockIndex;

	@SerializedName("Flags")
	private long flags;

	@SerializedName("Session")
	private String session;

	@SerializedName("Key")
	private String key;

	@SerializedName("Value")
	@JsonAdapter(Base64TypeAdapter.class)
	private byte[] value;

	public long getCreateIndex() {
		return createIndex;
	}

	public void setCreateIndex(long createIndex) {
		this.createIndex = createIndex;
	}

	public long getModifyIndex() {
		return modifyIndex;
	}

	public void setModifyIndex(long modifyIndex) {
		this.modifyIndex = modifyIndex;
	}

	public Long getLockIndex() {
		return lockIndex;
	}

	public void setLockIndex(Long lockIndex) {
		this.lockIndex = lockIndex;
	}

	public long getFlags() {
		return flags;
	}

	public void setFlags(long flags) {
		this.flags = flags;
	}

	public String getSession() {
		return session;
	}

	public void setSession(String session) {
		this.session = session;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public byte[] getValue() {
		return value;
	}

	public void setValue(byte[] value) {
		this.value = value;
	}

	@Override
	public String toString() {
		return "GetBinaryValue{" +
				"createIndex=" + createIndex +
				", modifyIndex=" + modifyIndex +
				", lockIndex=" + lockIndex +
				", flags=" + flags +
				", session='" + session + '\'' +
				", key='" + key + '\'' +
				", value=" + Arrays.toString(value) +
				'}';
	}
} public class GetValue {

	private static final Charset UTF_8 = Charset.forName("UTF-8");

	@SerializedName("CreateIndex")
	private long createIndex;

	@SerializedName("ModifyIndex")
	private long modifyIndex;

	@SerializedName("LockIndex")
	private Long lockIndex;

	@SerializedName("Flags")
	private long flags;

	@SerializedName("Session")
	private String session;

	@SerializedName("Key")
	private String key;

	@SerializedName("Value")
	private String value;

	public long getCreateIndex() {
		return createIndex;
	}

	public void setCreateIndex(long createIndex) {
		this.createIndex = createIndex;
	}

	public long getModifyIndex() {
		return modifyIndex;
	}

	public void setModifyIndex(long modifyIndex) {
		this.modifyIndex = modifyIndex;
	}

	public Long getLockIndex() {
		return lockIndex;
	}

	public void setLockIndex(Long lockIndex) {
		this.lockIndex = lockIndex;
	}

	public long getFlags() {
		return flags;
	}

	public void setFlags(long flags) {
		this.flags = flags;
	}

	public String getSession() {
		return session;
	}

	public void setSession(String session) {
		this.session = session;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public String getDecodedValue(Charset charset) {
		if (value == null) {
			return null;
		}
		if (charset == null) {
			charset = UTF_8;
		}
		return new String(Base64.getDecoder().decode(value), charset);
	}

	public String getDecodedValue() {
		return getDecodedValue(UTF_8);
	}

	@Override
	public String toString() {
		return "GetValue{" +
				"createIndex=" + createIndex +
				", modifyIndex=" + modifyIndex +
				", lockIndex=" + lockIndex +
				", flags=" + flags +
				", session='" + session + '\'' +
				", key='" + key + '\'' +
				", value='" + value + '\'' +
				'}';
	}
} public class PutParams implements UrlParameters {

	private long flags;
	private Long cas;
	private String acquireSession;
	private String releaseSession;

	public long getFlags() {
		return flags;
	}

	public void setFlags(long flags) {
		this.flags = flags;
	}

	public Long getCas() {
		return cas;
	}

	public void setCas(Long cas) {
		this.cas = cas;
	}

	public String getAcquireSession() {
		return acquireSession;
	}

	public void setAcquireSession(String acquireSession) {
		this.acquireSession = acquireSession;
	}

	public String getReleaseSession() {
		return releaseSession;
	}

	public void setReleaseSession(String releaseSession) {
		this.releaseSession = releaseSession;
	}

	@Override
	public List<String> toUrlParameters() {
		List<String> params = new ArrayList<String>();

		if (flags != 0) {
			params.add("flags=" + flags);
		}
		if (cas != null) {
			params.add("cas=" + cas);
		}
		if (acquireSession != null) {
			params.add("acquire=" + Utils.encodeValue(acquireSession));
		}
		if (releaseSession != null) {
			params.add("release=" + Utils.encodeValue(releaseSession));
		}

		return params;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (!(o instanceof PutParams)) {
			return false;
		}
		PutParams putParams = (PutParams) o;
		return flags == putParams.flags &&
			Objects.equals(cas, putParams.cas) &&
			Objects.equals(acquireSession, putParams.acquireSession) &&
			Objects.equals(releaseSession, putParams.releaseSession);
	}

	@Override
	public int hashCode() {
		return Objects.hash(flags, cas, acquireSession, releaseSession);
	}
} public interface QueryClient {

	public Response<QueryExecution> executePreparedQuery(String uuid, QueryParams queryParams);
} public final class QueryConsulClient implements QueryClient {

	private final ConsulRawClient rawClient;

	public QueryConsulClient(ConsulRawClient rawClient) { this.rawClient = rawClient; }

	public QueryConsulClient() { this(new ConsulRawClient()); }

	public QueryConsulClient(TLSConfig tlsConfig) { this(new ConsulRawClient(tlsConfig)); }

	public QueryConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public QueryConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public QueryConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	public QueryConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<QueryExecution> executePreparedQuery(String uuid, QueryParams queryParams) {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/query/" + uuid + "/execute", queryParams);

		if (httpResponse.getStatusCode() == 200) {
			QueryExecution queryExecution = GsonFactory.getGson().fromJson(httpResponse.getContent(), QueryExecution.class);
			return new Response<QueryExecution>(queryExecution, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}
} public class QueryExecution {

	public static class DNS {
		@SerializedName("TTL")
		private String ttl;

		public String getTtl() { return ttl; }

		public void setTtl(String ttl) { this.ttl = ttl; }

		@Override
		public String toString() {
			return "DNS{" +
				"ttl=" + ttl +
				'}';
		}
	}

	@SerializedName("Service")
	private String service;

	@SerializedName("Nodes")
	private List<QueryNode> nodes;

	@SerializedName("DNS")
	private DNS dns;

	@SerializedName("Datacenter")
	private String datacenter;

	@SerializedName("Failovers")
	private Integer failovers;

	public String getService() { return service; }

	public void setService(String service) { this.service = service; }

	public List<QueryNode> getNodes() { return nodes; }

	public void setNodes(List<QueryNode> nodes) { this.nodes = nodes; }

	public String getDatacenter() { return datacenter; }

	public void setDatacenter(String datacenter) { this.datacenter = datacenter; }

	public Integer getFailovers() { return failovers; }

	public void setFailovers(Integer failovers) { this.failovers = failovers; }

	@Override
	public String toString() {
		return "CatalogNode{" +
			"service=" + service +
			", nodes=" + nodes +
			", dns=" + dns +
			", datacenter=" + datacenter +
			", failovers=" + failovers +
			'}';
	}
} public interface SessionClient {

	public Response<String> sessionCreate(NewSession newSession, QueryParams queryParams);

	public Response<String> sessionCreate(NewSession newSession, QueryParams queryParams, String token);

	public Response<Void> sessionDestroy(String session, QueryParams queryParams);

	public Response<Void> sessionDestroy(String session, QueryParams queryParams, String token);

	Response<Session> getSessionInfo(String session, QueryParams queryParams);

	Response<Session> getSessionInfo(String session, QueryParams queryParams, String token);

	Response<List<Session>> getSessionNode(String node, QueryParams queryParams);

	Response<List<Session>> getSessionNode(String node, QueryParams queryParams, String token);

	Response<List<Session>> getSessionList(QueryParams queryParams);

	Response<List<Session>> getSessionList(QueryParams queryParams, String token);

	Response<Session> renewSession(String session, QueryParams queryParams);

	Response<Session> renewSession(String session, QueryParams queryParams, String token);
} public final class SessionConsulClient implements SessionClient {

	private final ConsulRawClient rawClient;

	public SessionConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public SessionConsulClient() {
		this(new ConsulRawClient());
	}

	public SessionConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public SessionConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	@Override
	public Response<String> sessionCreate(NewSession newSession, QueryParams queryParams) {
		return sessionCreate(newSession, queryParams, null);
	}

	@Override
	public Response<String> sessionCreate(NewSession newSession, QueryParams queryParams, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;

		String json = GsonFactory.getGson().toJson(newSession);
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/session/create", json, queryParams, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			Map<String, String> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<Map<String, String>>() {
			}.getType());
			return new Response<String>(value.get("ID"), httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Void> sessionDestroy(String session, QueryParams queryParams) {
		return sessionDestroy(session, queryParams, null);
	}

	@Override
	public Response<Void> sessionDestroy(String session, QueryParams queryParams, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/session/destroy/" + session, "", queryParams, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			return new Response<Void>(null, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<Session> getSessionInfo(String session, QueryParams queryParams) {
		return getSessionInfo(session, queryParams, null);
	}

	@Override
	public Response<Session> getSessionInfo(String session, QueryParams queryParams, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/session/info/" + session, queryParams, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			List<Session> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Session>>() {
			}.getType());

			if (value == null || value.isEmpty()) {
				return new Response<Session>(null, httpResponse);
			} else if (value.size() == 1) {
				return new Response<Session>(value.get(0), httpResponse);
			} else {
				throw new ConsulException("Strange response (list size=" + value.size() + ")");
			}
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Session>> getSessionNode(String node, QueryParams queryParams) {
		return getSessionNode(node, queryParams, null);
	}

	@Override
	public Response<List<Session>> getSessionNode(String node, QueryParams queryParams, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/session/node/" + node, queryParams, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			List<Session> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Session>>() {
			}.getType());
			return new Response<List<Session>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<Session>> getSessionList(QueryParams queryParams) {
		return getSessionList(queryParams, null);
	}

	@Override
	public Response<List<Session>> getSessionList(QueryParams queryParams, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/session/list", queryParams, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			List<Session> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Session>>() {
			}.getType());
			return new Response<List<Session>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	public Response<Session> renewSession(String session, QueryParams queryParams) {
		return renewSession(session, queryParams, null);
	}

	@Override
	public Response<Session> renewSession(String session, QueryParams queryParams, String token) {
		UrlParameters tokenParam = token != null ? new SingleUrlParameters("token", token) : null;
		HttpResponse httpResponse = rawClient.makePutRequest("/v1/session/renew/" + session, "", queryParams, tokenParam);

		if (httpResponse.getStatusCode() == 200) {
			List<Session> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<Session>>() {
			}.getType());

			if (value.size() == 1) {
				return new Response<Session>(value.get(0), httpResponse);
			} else {
				throw new ConsulException("Strange response (list size=" + value.size() + ")");
			}
		} else {
			throw new OperationException(httpResponse);
		}
	}
} public class Session {

	public static enum Behavior {
		@SerializedName("release")
		RELEASE,

		@SerializedName("delete")
		DELETE
	}

	@SerializedName("LockDelay")
	private long lockDelay;

	@SerializedName("Checks")
	private List<String> checks;

	@SerializedName("Node")
	private String node;

	@SerializedName("ID")
	private String id;

	@SerializedName("Name")
	private String name;

	@SerializedName("CreateIndex")
	private long createIndex;

	@SerializedName("ModifyIndex")
	private long modifyIndex;

	@SerializedName("TTL")
	private String ttl;

	@SerializedName("Behavior")
	private Behavior behavior;

	public long getLockDelay() {
		return lockDelay;
	}

	public void setLockDelay(long lockDelay) {
		this.lockDelay = lockDelay;
	}

	public List<String> getChecks() {
		return checks;
	}

	public void setChecks(List<String> checks) {
		this.checks = checks;
	}

	public String getNode() {
		return node;
	}

	public void setNode(String node) {
		this.node = node;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public long getCreateIndex() {
		return createIndex;
	}

	public void setCreateIndex(long createIndex) {
		this.createIndex = createIndex;
	}

	public long getModifyIndex() {
		return modifyIndex;
	}

	public void setModifyIndex(long modifyIndex) {
		this.modifyIndex = modifyIndex;
	}

	public String getTtl() {
		return ttl;
	}

	public void setTtl(String ttl) {
		this.ttl = ttl;
	}

	public Behavior getBehavior() {
		return behavior;
	}

	public void setBehavior(Behavior behavior) {
		this.behavior = behavior;
	}

	@Override
	public String toString() {
		return "Session{" +
				"lockDelay=" + lockDelay +
				", checks=" + checks +
				", node='" + node + '\'' +
				", id='" + id + '\'' +
				", name='" + name + '\'' +
				", createIndex=" + createIndex +
				", modifyIndex=" + modifyIndex +
				", ttl='" + ttl + '\'' +
				", behavior=" + behavior +
				'}';
	}
} public interface StatusClient {

	public Response<String> getStatusLeader();

	public Response<List<String>> getStatusPeers();
} public final class StatusConsulClient implements StatusClient {

	private final ConsulRawClient rawClient;

	public StatusConsulClient(ConsulRawClient rawClient) {
		this.rawClient = rawClient;
	}

	public StatusConsulClient() {
		this(new ConsulRawClient());
	}

	public StatusConsulClient(TLSConfig tlsConfig) {
		this(new ConsulRawClient(tlsConfig));
	}

	public StatusConsulClient(String agentHost) {
		this(new ConsulRawClient(agentHost));
	}

	public StatusConsulClient(String agentHost, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, tlsConfig));
	}

	public StatusConsulClient(String agentHost, int agentPort) {
		this(new ConsulRawClient(agentHost, agentPort));
	}

	public StatusConsulClient(String agentHost, int agentPort, TLSConfig tlsConfig) {
		this(new ConsulRawClient(agentHost, agentPort, tlsConfig));
	}

	@Override
	public Response<String> getStatusLeader() {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/status/leader");

		if (httpResponse.getStatusCode() == 200) {
			String value = GsonFactory.getGson().fromJson(httpResponse.getContent(), String.class);
			return new Response<String>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

	@Override
	public Response<List<String>> getStatusPeers() {
		HttpResponse httpResponse = rawClient.makeGetRequest("/v1/status/peers");

		if (httpResponse.getStatusCode() == 200) {
			List<String> value = GsonFactory.getGson().fromJson(httpResponse.getContent(), new TypeToken<List<String>>() {
			}.getType());
			return new Response<List<String>>(value, httpResponse);
		} else {
			throw new OperationException(httpResponse);
		}
	}

}
import com.ecwid.consul.transport.TLSConfig;
import com.ecwid.consul.v1.acl.AclClient;
import com.ecwid.consul.v1.acl.AclConsulClient;
import com.ecwid.consul.v1.acl.model.Acl;
import com.ecwid.consul.v1.acl.model.NewAcl;
import com.ecwid.consul.v1.acl.model.UpdateAcl;
import com.ecwid.consul.v1.agent.AgentClient;
import com.ecwid.consul.v1.agent.AgentConsulClient;
import com.ecwid.consul.v1.agent.model.*;
import com.ecwid.consul.v1.catalog.*;
import com.ecwid.consul.v1.catalog.model.*;
import com.ecwid.consul.v1.coordinate.CoordinateClient;
import com.ecwid.consul.v1.coordinate.CoordinateConsulClient;
import com.ecwid.consul.v1.coordinate.model.Datacenter;
import com.ecwid.consul.v1.event.EventClient;
import com.ecwid.consul.v1.event.EventConsulClient;
import com.ecwid.consul.v1.event.EventListRequest;
import com.ecwid.consul.v1.event.model.Event;
import com.ecwid.consul.v1.event.model.EventParams;
import com.ecwid.consul.v1.health.HealthChecksForServiceRequest;
import com.ecwid.consul.v1.health.HealthClient;
import com.ecwid.consul.v1.health.HealthConsulClient;
import com.ecwid.consul.v1.health.HealthServicesRequest;
import com.ecwid.consul.v1.health.model.HealthService;
import com.ecwid.consul.v1.kv.KeyValueClient;
import com.ecwid.consul.v1.kv.KeyValueConsulClient;
import com.ecwid.consul.v1.kv.model.GetBinaryValue;
import com.ecwid.consul.v1.kv.model.GetValue;
import com.ecwid.consul.v1.kv.model.PutParams;
import com.ecwid.consul.v1.query.QueryClient;
import com.ecwid.consul.v1.query.QueryConsulClient;
import com.ecwid.consul.v1.query.model.QueryExecution;
import com.ecwid.consul.v1.session.SessionClient;
import com.ecwid.consul.v1.session.SessionConsulClient;
import com.ecwid.consul.v1.session.model.NewSession;
import com.ecwid.consul.v1.session.model.Session;
import com.ecwid.consul.v1.status.StatusClient;
import com.ecwid.consul.v1.status.StatusConsulClient;
import java.util.List;
import java.util.Map;
package com.ecwid.consul.v1;



/**
 * Full consul-api client with all supported methods.
 * If you like to use more specific clients, please look at *Client classes (AclClient, AgentClient etc.)
 * <p>
 * Implementation notes:
 * Do not afraid of the class size :)
 * There aren't any 'smart' or specific methods - all methods in this class are just delegates and auto-generated by IntelliJ IDEA
 *
 * @author Vasily Vasilkov (vgv@ecwid.com)
 */
public class ConsulClient implements
		AclClient,
		AgentClient,
		CatalogClient,
		CoordinateClient,
		EventClient,
		HealthClient,
		KeyValueClient,
		QueryClient,
		SessionClient,
		StatusClient {

	private final AclClient aclClient;
	private final AgentClient agentClient;
	private final CatalogClient catalogClient;
	private final CoordinateClient coordinateClient;
	private final EventClient eventClient;
	private final HealthClient healthClient;
	private final KeyValueClient keyValueClient;
	private final QueryClient queryClient;
	private final SessionClient sessionClient;
	private final StatusClient statusClient;

	public ConsulClient(ConsulRawClient rawClient) {
		aclClient = new AclConsulClient(rawClient);
		agentClient = new AgentConsulClient(rawClient);
		catalogClient = new CatalogConsulClient(rawClient);
		coordinateClient = new CoordinateConsulClient(rawClient);
		eventClient = new EventConsulClient(rawClient);
		healthClient = new HealthConsulClient(rawClient);
		keyValueClient = new KeyValueConsulClient(rawClient);
		queryClient = new QueryConsulClient(rawClient);
		sessionClient = new SessionConsulClient(rawClient);
		statusClient = new StatusConsulClient(rawClient);
	}

	/**
	 * Consul client will connect to local consul agent on
	 * 'http://localhost:8500'
	 */
	public ConsulClient() {
		this(new ConsulRawClient());
	}

	/**
	 * Consul client will connect to local consul agent on
	 * 'http://localhost:8500'
	 *
	 * @param tlsConfig TLS configuration
	 */
	public ConsulClient(TLSConfig tlsConfig) {