You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ne...@apache.org on 2018/06/25 22:07:00 UTC
[trafficcontrol] 01/12: Added Java API foundations. Added
foundation for TrafficOps java api
This is an automated email from the ASF dual-hosted git repository.
neuman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
commit 213f65b9e64dc3db8e04c326078a3aa3dfb0358b
Author: nerdynick <ne...@gmail.com>
AuthorDate: Tue Dec 5 09:40:53 2017 -0700
Added Java API foundations. Added foundation for TrafficOps java api
---
traffic_control/clients/java/.gitignore | 4 +
traffic_control/clients/java/common/.gitignore | 1 +
traffic_control/clients/java/common/pom.xml | 29 ++++
.../cdn/traffic_control/RestApiSession.java | 171 +++++++++++++++++++
.../exception/InvalidJsonException.java | 26 +++
.../traffic_control/exception/LoginException.java | 26 +++
.../exception/OperationException.java | 26 +++
.../exception/TrafficControlException.java | 26 +++
traffic_control/clients/java/pom.xml | 47 ++++++
traffic_control/clients/java/trafficops/.gitignore | 1 +
traffic_control/clients/java/trafficops/pom.xml | 40 +++++
.../com/comcast/cdn/traffic_control/TOSession.java | 181 +++++++++++++++++++++
.../comcast/cdn/traffic_control/models/Alert.java | 20 +++
.../cdn/traffic_control/models/Response.java | 27 +++
.../comcast/cdn/traffic_control/TOSessionTest.java | 85 ++++++++++
.../trafficops/src/test/resources/logback-test.xml | 12 ++
16 files changed, 722 insertions(+)
diff --git a/traffic_control/clients/java/.gitignore b/traffic_control/clients/java/.gitignore
new file mode 100644
index 0000000..0ac589d
--- /dev/null
+++ b/traffic_control/clients/java/.gitignore
@@ -0,0 +1,4 @@
+.settings
+.project
+.classpath
+.factorypath
diff --git a/traffic_control/clients/java/common/.gitignore b/traffic_control/clients/java/common/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/traffic_control/clients/java/common/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/traffic_control/clients/java/common/pom.xml b/traffic_control/clients/java/common/pom.xml
new file mode 100644
index 0000000..9c40861
--- /dev/null
+++ b/traffic_control/clients/java/common/pom.xml
@@ -0,0 +1,29 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.comcast.cdn.traffic_control</groupId>
+ <artifactId>traffic-control-java-client</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>traffic-control-java-client-common</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpasyncclient</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/RestApiSession.java b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/RestApiSession.java
new file mode 100644
index 0000000..941d4c4
--- /dev/null
+++ b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/RestApiSession.java
@@ -0,0 +1,171 @@
+package com.comcast.cdn.traffic_control;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.apache.http.message.BasicHeader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.comcast.cdn.traffic_control.exception.OperationException;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+
+@AutoValue
+public abstract class RestApiSession implements Closeable {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(RestApiSession.class);
+
+ private static final String URL_FORMAT_STR = "%s://%s:%s/%s/%s/%s";
+
+ public static final String DEFAULT_API_PATH = "api";
+ public static final String DEFAULT_API_VERSION = "1.2";
+ public static final ImmutableList<Header> DEFAULT_HEADERS;
+ static {
+ DEFAULT_HEADERS = ImmutableList.<Header>builder()
+ .add(new BasicHeader("Content-Type", "application/json; charset=UTF-8")).build();
+ };
+
+ private CloseableHttpAsyncClient httpclient;
+
+ public void open() {
+ if (httpclient == null) {
+ RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.DEFAULT).build();
+ CookieStore cookieStore = new BasicCookieStore();
+ HttpClientContext context = HttpClientContext.create();
+ context.setCookieStore(cookieStore);
+
+ httpclient = HttpAsyncClients.custom()
+ .setDefaultRequestConfig(globalConfig)
+ .setDefaultCookieStore(cookieStore).build();
+ }
+
+ if (!httpclient.isRunning()) {
+ httpclient.start();
+ }
+ }
+
+ public boolean isRunning() {
+ if (httpclient == null) {
+ return false;
+ } else {
+ return httpclient.isRunning();
+ }
+ }
+
+ public void close() throws IOException {
+ if (httpclient != null) {
+ httpclient.close();
+ httpclient = null;
+ }
+ }
+
+ public String buildUrl(String path) {
+ return String.format(URL_FORMAT_STR, this.ssl() ?"https":"http", this.host(), this.port(), this.apiBasePath(),
+ this.apiVersion(), path);
+ }
+
+ public CompletableFuture<HttpResponse> get(String url) {
+ return execute(RequestBuilder.get(url));
+ }
+
+ public CompletableFuture<HttpResponse> post(String url, String body) {
+ final HttpEntity e = new StringEntity(body, Charsets.UTF_8);
+ return execute(RequestBuilder.post()
+ .setUri(url)
+ .setEntity(e));
+ }
+
+ public CompletableFuture<HttpResponse> execute(RequestBuilder request) {
+ for(Header h: this.defaultHeaders()) {
+ request.addHeader(h);
+ }
+
+ return this.execute(request.build());
+ }
+
+ private CompletableFuture<HttpResponse> execute(HttpUriRequest request) {
+ final CompletableFutureCallback future = new CompletableFutureCallback();
+ try {
+ this.open();
+ this.httpclient.execute(request, future);
+ } catch(Throwable e) {
+ future.completeExceptionally(e);
+ }
+
+ return future;
+ }
+
+ private class CompletableFutureCallback extends CompletableFuture<HttpResponse> implements FutureCallback<HttpResponse>{
+ @Override
+ public void completed(HttpResponse result) {
+ this.complete(result);
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ this.completeExceptionally(ex);
+ }
+
+ @Override
+ public void cancelled() {
+ this.completeExceptionally(new OperationException("HTTP Request was cancelled"));
+ }
+ }
+
+ public abstract String host();
+
+ public abstract int port();
+
+ public abstract String apiVersion();
+
+ public abstract String apiBasePath();
+
+ public abstract ImmutableList<Header> defaultHeaders();
+
+ public abstract boolean ssl();
+
+ static Builder builder() {
+ return new AutoValue_RestApiSession.Builder()
+ .setApiBasePath(DEFAULT_API_PATH)
+ .setApiVersion(DEFAULT_API_VERSION)
+ .setDefaultHeaders(DEFAULT_HEADERS);
+ }
+
+ public abstract Builder toBuilder();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract RestApiSession build();
+
+ public abstract Builder setHost(String host);
+
+ public abstract Builder setPort(int port);
+
+ public abstract Builder setApiVersion(String version);
+
+ public abstract Builder setApiBasePath(String version);
+
+ public abstract Builder setSsl(boolean ssl);
+
+ public abstract Builder setDefaultHeaders(ImmutableList<Header> headers);
+ public abstract ImmutableList.Builder<Header> defaultHeadersBuilder();
+
+ }
+}
diff --git a/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/InvalidJsonException.java b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/InvalidJsonException.java
new file mode 100644
index 0000000..696574b
--- /dev/null
+++ b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/InvalidJsonException.java
@@ -0,0 +1,26 @@
+package com.comcast.cdn.traffic_control.exception;
+
+public class InvalidJsonException extends TrafficControlException {
+ private static final long serialVersionUID = 1884362711438565843L;
+
+ public InvalidJsonException() {
+ super();
+ }
+
+ public InvalidJsonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public InvalidJsonException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidJsonException(String message) {
+ super(message);
+ }
+
+ public InvalidJsonException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/LoginException.java b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/LoginException.java
new file mode 100644
index 0000000..83fcdc6
--- /dev/null
+++ b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/LoginException.java
@@ -0,0 +1,26 @@
+package com.comcast.cdn.traffic_control.exception;
+
+public class LoginException extends TrafficControlException {
+ private static final long serialVersionUID = -5021620597469977194L;
+
+ public LoginException() {
+ super();
+ }
+
+ public LoginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public LoginException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public LoginException(String message) {
+ super(message);
+ }
+
+ public LoginException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/OperationException.java b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/OperationException.java
new file mode 100644
index 0000000..1a019fa
--- /dev/null
+++ b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/OperationException.java
@@ -0,0 +1,26 @@
+package com.comcast.cdn.traffic_control.exception;
+
+public class OperationException extends TrafficControlException {
+ private static final long serialVersionUID = 8799467021892976240L;
+
+ public OperationException() {
+ super();
+ }
+
+ public OperationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public OperationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public OperationException(String message) {
+ super(message);
+ }
+
+ public OperationException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/TrafficControlException.java b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/TrafficControlException.java
new file mode 100644
index 0000000..617db9d
--- /dev/null
+++ b/traffic_control/clients/java/common/src/main/java/com/comcast/cdn/traffic_control/exception/TrafficControlException.java
@@ -0,0 +1,26 @@
+package com.comcast.cdn.traffic_control.exception;
+
+public class TrafficControlException extends Exception {
+ private static final long serialVersionUID = 914940907727369814L;
+
+ public TrafficControlException() {
+ super();
+ }
+
+ public TrafficControlException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public TrafficControlException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TrafficControlException(String message) {
+ super(message);
+ }
+
+ public TrafficControlException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/traffic_control/clients/java/pom.xml b/traffic_control/clients/java/pom.xml
new file mode 100644
index 0000000..c921a8e
--- /dev/null
+++ b/traffic_control/clients/java/pom.xml
@@ -0,0 +1,47 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.comcast.cdn.traffic_control</groupId>
+ <artifactId>traffic-control-java-client</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <modules>
+ <module>common</module>
+ <module>trafficops</module>
+ </modules>
+ <properties>
+ <java.version>1.8</java.version>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.25</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpasyncclient</artifactId>
+ <version>4.1.3</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>23.5-jre</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+</project>
\ No newline at end of file
diff --git a/traffic_control/clients/java/trafficops/.gitignore b/traffic_control/clients/java/trafficops/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/traffic_control/clients/java/trafficops/pom.xml b/traffic_control/clients/java/trafficops/pom.xml
new file mode 100644
index 0000000..2c3a5b3
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/pom.xml
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.comcast.cdn.traffic_control</groupId>
+ <artifactId>traffic-control-java-client</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </parent>
+ <artifactId>traffic-control-java-client-trafficops</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>com.comcast.cdn.traffic_control</groupId>
+ <artifactId>traffic-control-java-client-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.2</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.1.3</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <version>2.12.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/TOSession.java b/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/TOSession.java
new file mode 100644
index 0000000..82791f4
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/TOSession.java
@@ -0,0 +1,181 @@
+package com.comcast.cdn.traffic_control;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiConsumer;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.StringEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.comcast.cdn.traffic_control.exception.LoginException;
+import com.comcast.cdn.traffic_control.exception.OperationException;
+import com.comcast.cdn.traffic_control.models.Alert;
+import com.comcast.cdn.traffic_control.models.Response;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+@AutoValue
+public abstract class TOSession {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(TOSession.class);
+
+ private static final Gson gson = new GsonBuilder()
+ .create();
+
+ private boolean isLoggedIn = false;
+
+ public String toUrl() {
+ return this.restClient().buildUrl("/");
+ }
+ public boolean isLoggedIn() {
+ return isLoggedIn;
+ }
+
+ public CompletableFuture<Boolean> login(final String username, final String password) {
+ final String url = this.restClient().buildUrl("user/login.json");
+
+ return ResponseFuture.builder()
+ .setHandleException((f,t)-> {
+ f.completeExceptionally(new LoginException(String.format("Failed to login with username %s", username), t));
+ })
+ .setMethod(ResponseFuture.Method.POST)
+ .setUrl(url)
+ .setBody(gson.toJson(ImmutableMap.<String,String>of("u", username, "p", password))).build()
+ .thenApply(r->{
+ isLoggedIn = true;
+ return true;
+ });
+ }
+
+ public CompletableFuture<Response.CollectionResponse> getServers(){
+ final String url = this.restClient().buildUrl("servers.json");
+ return ResponseFuture.builder(Response.CollectionResponse.class)
+ .setMethod(ResponseFuture.Method.GET)
+ .setUrl(url)
+ .setSession(this.restClient())
+ .build();
+ }
+
+ public CompletableFuture<Response.CollectionResponse> getDeliveryServices(){
+ final String url = this.restClient().buildUrl("deliveryservices.json");
+ LOG.debug("getDeliveryService url {}", url);
+ return ResponseFuture.builder(Response.CollectionResponse.class)
+ .setMethod(ResponseFuture.Method.GET)
+ .setUrl(url)
+ .setSession(this.restClient())
+ .build();
+ }
+
+
+ @AutoValue
+ protected abstract static class ResponseFuture<T extends Response> extends CompletableFuture<T> implements BiConsumer<HttpResponse, Throwable> {
+ private static final Logger LOG = LoggerFactory.getLogger(ResponseFuture.class);
+ public static enum Method{
+ POST , GET
+ }
+
+ public abstract Optional<BiConsumer<ResponseFuture<T>, Throwable>> handleException();
+ public abstract Class<T> responseType();
+ public abstract Method method();
+ public abstract String url();
+ public abstract RestApiSession session();
+ public abstract Optional<String> body();
+
+ public static <T extends Response> Builder<T> builder(Class<T> response) {
+ return new AutoValue_TOSession_ResponseFuture.Builder<T>()
+ .setResponseType(response);
+ }
+ public static Builder<Response> builder() {
+ return builder(Response.class);
+ }
+
+ public ResponseFuture<T> execute(){
+ LOG.debug("Requesting: {} {}", this.method(), this.url());
+ RequestBuilder rBuilder = RequestBuilder.create(this.method().toString());
+ if(this.body().isPresent()) {
+ rBuilder.setEntity(new StringEntity(this.body().get(), Charsets.UTF_8));
+ }
+ this.session().execute(rBuilder).whenComplete(this);
+ return this;
+ }
+
+ @AutoValue.Builder
+ public abstract static class Builder<T extends Response> {
+ public ResponseFuture<T> build(){
+ return autoBuild().execute();
+ }
+ protected abstract ResponseFuture<T> autoBuild();
+ public abstract Builder<T> setHandleException(BiConsumer<ResponseFuture<T>, Throwable> function);
+ public abstract Builder<T> setResponseType(Class<T> respone);
+ public abstract Builder<T> setMethod(Method method);
+ public abstract Builder<T> setUrl(String url);
+ public abstract Builder<T> setSession(RestApiSession session);
+ public abstract Builder<T> setBody(String body);
+ }
+
+ @Override
+ public void accept(HttpResponse res, Throwable u) {
+ try {
+ switch(res.getStatusLine().getStatusCode()) {
+ case 200:
+ break;
+ case 401:
+ _handleException(new LoginException("Login required"));
+ return;
+ default:
+ _handleException(new OperationException(String.format("None 200 response: %s %s", res.getStatusLine().getStatusCode(), res.getStatusLine().getReasonPhrase())));
+ return;
+ }
+
+ InputStreamReader r = new InputStreamReader(res.getEntity().getContent());
+ T resp = gson.fromJson(r, responseType());
+ if(resp.getAlerts() != null) {
+ for(Alert a: resp.getAlerts()) {
+ if("error".equals(a.getLevel())) {
+ _handleException(new OperationException("Recieved error from server: "+ a.getText()));
+ return;
+ }
+ }
+ }
+
+ this.complete(resp);
+ } catch (UnsupportedOperationException | IOException e) {
+ _handleException(new OperationException("Reading response failed", e));
+ return;
+ }
+ }
+
+ private void _handleException(Throwable t) {
+ if(handleException().isPresent()) {
+ handleException().get().accept(this, t);
+ }
+
+ if(!this.isDone()) {
+ this.completeExceptionally(t);
+ }
+ }
+ }
+
+ public abstract RestApiSession restClient();
+
+ static Builder builder() {
+ return new AutoValue_TOSession.Builder();
+ }
+ public abstract Builder toBuilder();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract TOSession build();
+
+ public abstract Builder setRestClient(RestApiSession restClient);
+ public abstract RestApiSession.Builder restClientBuilder();
+ }
+}
diff --git a/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/models/Alert.java b/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/models/Alert.java
new file mode 100644
index 0000000..0a6e2f9
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/models/Alert.java
@@ -0,0 +1,20 @@
+package com.comcast.cdn.traffic_control.models;
+
+public class Alert {
+ private String level;
+ private String text;
+
+ public String getLevel() {
+ return level;
+ }
+ public void setLevel(String level) {
+ this.level = level;
+ }
+ public String getText() {
+ return text;
+ }
+ public void setText(String text) {
+ this.text = text;
+ }
+
+}
diff --git a/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/models/Response.java b/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/models/Response.java
new file mode 100644
index 0000000..987aee2
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/src/main/java/com/comcast/cdn/traffic_control/models/Response.java
@@ -0,0 +1,27 @@
+package com.comcast.cdn.traffic_control.models;
+
+import java.util.List;
+import java.util.Map;
+
+public class Response {
+ private List<Alert> alerts;
+
+ public List<Alert> getAlerts() {
+ return alerts;
+ }
+ public void setAlerts(List<Alert> alerts) {
+ this.alerts = alerts;
+ }
+
+ public class CollectionResponse extends Response {
+ private List<Map<String, Object>> response;
+
+ public List<Map<String, Object>> getResponse() {
+ return response;
+ }
+
+ public void setResponse(List<Map<String, Object>> response) {
+ this.response = response;
+ }
+ }
+}
diff --git a/traffic_control/clients/java/trafficops/src/test/java/com/comcast/cdn/traffic_control/TOSessionTest.java b/traffic_control/clients/java/trafficops/src/test/java/com/comcast/cdn/traffic_control/TOSessionTest.java
new file mode 100644
index 0000000..efa310e
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/src/test/java/com/comcast/cdn/traffic_control/TOSessionTest.java
@@ -0,0 +1,85 @@
+package com.comcast.cdn.traffic_control;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.message.BasicStatusLine;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.comcast.cdn.traffic_control.exception.LoginException;
+import com.comcast.cdn.traffic_control.models.Response.CollectionResponse;
+
+public class TOSessionTest {
+ private static final Logger LOG = LoggerFactory.getLogger(TOSessionTest.class);
+
+ public static final String DeliveryService_Good_Response = "{\"response\": [{\"cachegroup\": \"us-co-denver\"}]}";
+
+ private RestApiSession sessionMock;
+
+ @Before
+ public void before() {
+ sessionMock = Mockito.mock(RestApiSession.class, Mockito.CALLS_REAL_METHODS);
+ }
+ @After
+ public void after() {
+ sessionMock=null;
+ }
+
+ @Test
+ public void testBuild() {
+ TOSession.builder().setRestClient(sessionMock).build();
+ }
+
+ @Test(expected=LoginException.class)
+ public void test401Response() throws Throwable {
+ HttpResponse resp = Mockito.mock(HttpResponse.class);
+ Mockito.when(resp.getStatusLine()).thenReturn(new BasicStatusLine(HttpVersion.HTTP_1_0, 401, "Not Auth"));
+
+ CompletableFuture<HttpResponse> f = new CompletableFuture<>();
+ f.complete(resp);
+
+ Mockito.doReturn(f).when(sessionMock).execute(Mockito.any(RequestBuilder.class));
+
+ TOSession session = TOSession.builder().setRestClient(sessionMock).build();
+
+ try {
+ session.getDeliveryServices().get();
+ } catch(Throwable e) {
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void deliveryServices() throws Throwable {
+ HttpResponse resp = Mockito.mock(HttpResponse.class);
+ Mockito.doReturn(new BasicStatusLine(HttpVersion.HTTP_1_0, 200, "Ok")).when(resp).getStatusLine();
+ Mockito.doReturn(new StringEntity(DeliveryService_Good_Response)).when(resp).getEntity();
+
+ CompletableFuture<HttpResponse> f = new CompletableFuture<>();
+ f.complete(resp);
+
+ Mockito.doReturn(f).when(sessionMock).execute(Mockito.any(RequestBuilder.class));
+
+ TOSession session = TOSession.builder().setRestClient(sessionMock).build();
+ CollectionResponse cResp = session.getDeliveryServices().get();
+
+ assertNotNull(cResp);
+ assertNotNull(cResp.getResponse());
+ assertEquals(1, cResp.getResponse().size());
+
+ final Map<String,Object> service = cResp.getResponse().get(0);
+ assertEquals("us-co-denver", service.get("cachegroup"));
+ LOG.debug("Service: {}", service);
+ }
+}
diff --git a/traffic_control/clients/java/trafficops/src/test/resources/logback-test.xml b/traffic_control/clients/java/trafficops/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..185b678
--- /dev/null
+++ b/traffic_control/clients/java/trafficops/src/test/resources/logback-test.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<configuration>
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p] [%t] %C:%L %m%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="DEBUG">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
\ No newline at end of file