Merge branch 'stable-2.13'

* stable-2.13:
  Replace Atlassian Library with vanilla HTTP calls
  Cleanup wsdl stuff, no longer used with Rest-API

Change-Id: I4935818816d59ef00d2614df66094cd54779b419
diff --git a/BUILD b/BUILD
index a17d7dc..8762bf6 100644
--- a/BUILD
+++ b/BUILD
@@ -14,10 +14,6 @@
     ],
     deps = [
         "//plugins/its-base",
-        "@atlassian_httpclient_apache_httpcomponents//jar",
-        "@atlassian_util_concurrent//jar",
-        "@jira_rest_java_client_api//jar",
-        "@jira_rest_java_client_core//jar",
     ],
 )
 
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
deleted file mode 100644
index aac67ce..0000000
--- a/external_plugin_deps.bzl
+++ /dev/null
@@ -1,214 +0,0 @@
-load("//tools/bzl:maven_jar.bzl", "maven_jar", "MAVEN_LOCAL")
-
-ATLASSIAN_REPO = 'https://maven.atlassian.com/repository/public/'
-
-def external_plugin_deps():
-  maven_jar(
-    name = 'jira_rest_java_client_core',
-    artifact = 'com.atlassian.jira:jira-rest-java-client-core:3.0.0',
-    deps = [
-      '@atlassian_httpclient_apache_httpcomponents//jar',
-      '@atlassian_util_concurrent//jar',
-      '@httpmime//jar',
-      '@jersey_client//jar',
-      '@jersey_json//jar',
-      '@jira_rest_java_client_api//jar',
-    ],
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'atlassian_httpclient_apache_httpcomponents',
-    artifact = 'com.atlassian.httpclient:atlassian-httpclient-apache-httpcomponents:0.13.2',
-    deps = [
-      '@atlassian_event//jar',
-      '@atlassian_httpclient_api//jar',
-      '@httpasyncclient//jar',
-      '@httpasyncclient_cache//jar',
-      '@httpclient_cache//jar',
-      '@httpcore//jar',
-      '@httpcore_nio//jar',
-      '@sal_api//jar',
-      '@log_api//jar',
-      '@spring_context//jar',
-    ],
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'spring_context',
-    artifact = 'org.springframework:spring-context:2.5.6',
-    deps = [
-      '@aopalliance//jar',
-      '@spring_core//jar',
-      '@spring_beans//jar',
-    ],
-    sha1 = '983416e612875bdcf877dad4c9d5d77ae37e06ee',
-    exclude = ["META-INF/license.txt"],
-  )
-
-  maven_jar(
-    name = 'spring_beans',
-    artifact = 'org.springframework:spring-beans:2.5.6',
-    sha1 = '449ea46b27426eb846611a90b2fb8b4dcf271191',
-    exclude = ["META-INF/license.txt"],
-  )
-
-  maven_jar(
-    name = 'spring_core',
-    artifact = 'org.springframework:spring-core:2.5.6',
-    sha1 = 'c450bc49099430e13d21548d1e3d1a564b7e35e9',
-    exclude = ["META-INF/license.txt"],
-  )
-
-  maven_jar(
-    name = 'httpclient_cache',
-    artifact = 'org.apache.httpcomponents:httpclient-cache:4.4.1',
-    sha1 = '6c9ba9c38bca8742d5745bb27bcd4b9c7542ea24',
-    deps = [
-      '@httpclient//jar:neverlink',
-    ],
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'httpasyncclient_cache',
-    artifact = 'org.apache.httpcomponents:httpasyncclient-cache:4.1.1',
-    sha1 = '93601cc6fe8f4b042260c6cda9d52fffb62ae31a',
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name  ='atlassian_event',
-    artifact = 'com.atlassian.event:atlassian-event:2.2.0',
-    sha1 = 'c7a1b83e92fdb05e02ba717fbce3b7551ce945f7',
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'sal_api',
-    artifact = 'com.atlassian.sal:sal-api:2.7.0',
-    sha1 = 'b0d49ec14b5c823c24821bfbc8cd618525390a1b',
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'atlassian_httpclient_api',
-    artifact = 'com.atlassian.httpclient:atlassian-httpclient-api:0.13.2',
-    deps = [
-      '@atlassian_httpclient_spi//jar',
-    ],
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'atlassian_httpclient_spi',
-    artifact = 'com.atlassian.httpclient:atlassian-httpclient-spi:0.13.2',
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'atlassian_util_concurrent',
-    artifact = 'com.atlassian.util.concurrent:atlassian-util-concurrent:2.4.0-M9',
-    sha1 = 'e8469a31d1999f5459a2c5a61234755f625fc3f7',
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'jira_rest_java_client_api',
-    artifact = 'com.atlassian.jira:jira-rest-java-client-api:3.0.0',
-    repository = ATLASSIAN_REPO,
-  )
-
-  maven_jar(
-    name = 'jersey_client',
-    artifact = 'com.sun.jersey:jersey-client:1.5',
-    deps = [
-      '@jersey_core//jar',
-    ],
-    sha1 = '4dc285245a495c2682b743c81cb67a7d1e8b2e7d',
-  )
-
-  maven_jar(
-    name = 'jersey_core',
-    artifact = 'com.sun.jersey:jersey-core:1.5',
-    sha1 = '955fa871051acd23841ff75087b190278228920a',
-  )
-
-  maven_jar(
-    name = 'jersey_json',
-    artifact = 'com.sun.jersey:jersey-json:1.5',
-    deps = [
-      '@jackson_core_asl//jar',
-      '@jackson_mapper_asl//jar',
-      '@jackson_xc//jar',
-      '@jaxb_impl//jar',
-      '@jettison//jar',
-    ],
-    sha1 = '8d77a3d4277016277cb85b98c179a2a7e9ec6dfb',
-  )
-
-  maven_jar(
-    name = 'jettison',
-    artifact = 'org.codehaus.jettison:jettison:1.1',
-    deps = [
-      '@stax_api_1//jar',
-    ],
-    sha1 = '1a01a2a1218fcf9faa2cc2a6ced025bdea687262',
-  )
-
-  maven_jar(
-    name = 'stax_api_1',
-    artifact = 'stax:stax-api:1.0.1',
-    sha1 = '49c100caf72d658aca8e58bd74a4ba90fa2b0d70',
-    attach_source = False,
-  )
-
-  maven_jar(
-    name = 'jaxb_impl',
-    artifact = 'com.sun.xml.bind:jaxb-impl:2.2.3',
-    deps = [
-      '@jaxb_api//jar',
-    ],
-    sha1 = '565307a5e9c563666418e70b22c07886104e6ba7',
-  )
-
-  maven_jar(
-    name = 'jaxb_api',
-    artifact = 'javax.xml.bind:jaxb-api:2.2.2',
-    deps = [
-      '@stax_api_2//jar',
-    ],
-    sha1 = 'aeb3021ca93dde265796d82015beecdcff95bf09',
-  )
-
-  maven_jar(
-    name = 'stax_api_2',
-    artifact = 'javax.xml.stream:stax-api:1.0-2',
-    sha1 = 'd6337b0de8b25e53e81b922352fbea9f9f57ba0b',
-    attach_source = False,
-  )
-
-  maven_jar(
-    name = 'jackson_core_asl',
-    artifact = 'org.codehaus.jackson:jackson-core-asl:1.5.5',
-    sha1 = 'beb1ba1c1b84c2f2c54b8f1ce63224ca0f98334d',
-  )
-
-  maven_jar(
-    name = 'jackson_mapper_asl',
-    artifact = 'org.codehaus.jackson:jackson-mapper-asl:1.5.5',
-    sha1 = '908a1589e4ef52dc81252bc18d678bd232423c10',
-  )
-
-  maven_jar(
-    name = 'jackson_jaxrs',
-    artifact = 'org.codehaus.jackson:jackson-jaxrs:1.5.5',
-    sha1 = '2141d77b65d5bb36a2cdafb1010b8704c3fd4585',
-  )
-
-  maven_jar(
-    name = 'jackson_xc',
-    artifact = 'org.codehaus.jackson:jackson-xc:1.5.5',
-    sha1 = '58811cfa31b5355d0146aae33b3fc3fee661d5bc',
-  )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java
index e0c8bea..c0340a2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/InitJira.java
@@ -14,16 +14,12 @@
 
 package com.googlesource.gerrit.plugins.its.jira;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.pgm.init.api.AllProjectsConfig;
 import com.google.gerrit.pgm.init.api.AllProjectsNameOnInitProvider;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
 import com.google.gerrit.pgm.init.api.InitFlags;
 import com.google.gerrit.pgm.init.api.Section;
-import com.google.gerrit.pgm.init.api.ConsoleUI;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -32,10 +28,12 @@
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
+import java.io.IOException;
+import java.util.Arrays;
+
 /** Initialize the GitRepositoryManager configuration section. */
 @Singleton
 class InitJira extends InitIts {
-  private static final String COMMENT_LINK_SECTION = "commentLink";
   private final String pluginName;
   private final Section.Factory sections;
   private final InitFlags flags;
@@ -125,7 +123,7 @@
       new JiraClient(jiraUrl, jiraUsername, jiraPassword).sysInfo().getVersion();
       ui.message("[OK]\n");
       return true;
-    } catch (URISyntaxException e) {
+    } catch (IOException e) {
       ui.message("*FAILED* (%s)\n", e.toString());
       return false;
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java
index 348c135..c0d7376 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraClient.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2013 The Android Open Source Project
+// Copyright (C) 2013 - 2017 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,133 +14,145 @@
 
 package com.googlesource.gerrit.plugins.its.jira;
 
-import com.atlassian.jira.rest.client.api.IssueRestClient;
-import com.atlassian.jira.rest.client.api.JiraRestClient;
-import com.atlassian.jira.rest.client.api.JiraRestClientFactory;
-import com.atlassian.jira.rest.client.api.RestClientException;
-import com.atlassian.jira.rest.client.api.domain.Comment;
-import com.atlassian.jira.rest.client.api.domain.Issue;
-import com.atlassian.jira.rest.client.api.domain.ServerInfo;
-import com.atlassian.jira.rest.client.api.domain.Transition;
-import com.atlassian.jira.rest.client.api.domain.input.TransitionInput;
-import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
-import com.atlassian.util.concurrent.Promise;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_FORBIDDEN;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+
+import com.google.gson.Gson;
+
 import com.googlesource.gerrit.plugins.its.base.its.InvalidTransitionException;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraComment;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraIssue;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraProject;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraRestApi;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraRestApiProvider;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraServerInfo;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraTransition;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.List;
 
-/**
- * Jira Rest Client.
- */
 public class JiraClient {
   private static final Logger log = LoggerFactory.getLogger(JiraClient.class);
 
-  private JiraRestClient client = null;
+  private final JiraRestApiProvider apiBuilder;
+  private final Gson gson;
 
   /**
-   * @param url  jira url
+   * @param url jira url
    * @param user username of the jira user
    * @param pass password of the jira user
-   * @throws URISyntaxException
    */
-  public JiraClient(String url, String user, String pass) throws URISyntaxException {
-    URI jiraUri = new URI(url);
-    log.debug("Trying to access Jira at " + jiraUri);
-    JiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
-    client = factory.createWithBasicHttpAuthentication(jiraUri, user, pass);
-    log.debug("Initialized jira client " + client);
-  }
-
-  /**
-   * @param issueKey Issue id
-   * @return Issueobjekt by issue id
-   * @throws RestClientException
-   */
-  public Issue getIssue(String issueKey) throws RestClientException {
-    IssueRestClient issueClient = this.client.getIssueClient();
-    return issueClient.getIssue(issueKey).claim();
+  public JiraClient(String url, String user, String pass)
+      throws MalformedURLException {
+    this.apiBuilder = new JiraRestApiProvider(url, user, pass);
+    this.gson = new Gson();
   }
 
   /**
    * @param issueKey Jira Issue key
    * @return true if issue exists
    */
-  public boolean issueExists(String issueKey) throws RestClientException {
-    boolean ret = true;
-    try{
-      getIssue(issueKey);
-    } catch (RestClientException e) {
-      if (e.getStatusCode().get() == 404){
+  public boolean issueExists(String issueKey) throws IOException {
+    JiraRestApi<JiraIssue> api = apiBuilder.getIssue();
+
+    api.doGet("/" + issueKey, HTTP_OK,
+        new int[] {HTTP_NOT_FOUND, HTTP_FORBIDDEN});
+    Integer code = api.getResponseCode();
+    switch (code) {
+      case HTTP_OK:
+        return true;
+      case HTTP_NOT_FOUND:
         log.error("Issue " + issueKey + " not found ");
-        ret = false;
-      } else {
-        throw e;
-      }
+        return false;
+      case HTTP_FORBIDDEN:
+        log.error("No permission to read Issue " + issueKey);
+        return false;
+      default:
+        // Cannot happen due to passCodes filter
+        throw new IOException(
+            "Unexpected HTTP code received:" + code.toString());
     }
-    return ret;
   }
 
   /**
    * @param issueKey Jira Issue key
    * @return Iterable of available transitions
-   * @throws RestClientException
+   * @throws IOException
    */
-  public Iterable<Transition> getTransitions(String issueKey) throws RestClientException {
-    return client.getIssueClient().getTransitions(getIssue(issueKey)).claim();
+  public List<JiraTransition.Item> getTransitions(String issueKey)
+      throws IOException {
+
+    JiraRestApi<JiraTransition> api =
+        apiBuilder.get(JiraTransition.class, "/issue");
+    return Arrays.asList(
+        api.doGet("/" + issueKey + "/transitions", HTTP_OK).transitions);
   }
 
   /**
    * @param issueKey Jira Issue key
-   * @param comment  Comment  to be added
-   * @throws RestClientException
+   * @param comment String to be added
+   * @throws IOException
    */
-  public void addComment(String issueKey, Comment comment) throws RestClientException, URISyntaxException {
-    log.debug("Trying to add comment for issue " + issueKey);
-    Issue issue = getIssue(issueKey);
-    URI issueUri;
-    issueUri = new URI(issue.getSelf().toString() + "/comment/");
-    IssueRestClient issueClient = client.getIssueClient();
-    Promise<Void> promise = issueClient.addComment(issueUri, comment);
-    promise.claim();
-    log.debug("Comment added to issue " + issueKey);
+  public void addComment(String issueKey, String comment) throws IOException {
+
+    if (issueExists(issueKey)) {
+      log.debug("Trying to add comment for issue {}", issueKey);
+      apiBuilder.getIssue().doPost("/" + issueKey + "/comment",
+          gson.toJson(new JiraComment(comment)), HTTP_CREATED);
+      log.debug("Comment added to issue {}", issueKey);
+    } else {
+      log.error("Issue {} does not exist or no access permission", issueKey);
+    }
   }
 
   /**
-   * @param issueKey   Jira Issue key
-   * @param transition Transition to perform
+   * @param issueKey Jira Issue key
+   * @param transition JiraTransition.Item to perform
    * @return true if successful
    */
-  public boolean doTransition(String issueKey, String transition) throws RestClientException, InvalidTransitionException {
-    Transition t = getTransitionByName(getTransitions(issueKey), transition);
+  public boolean doTransition(String issueKey, String transition)
+      throws IOException, InvalidTransitionException {
+    log.debug("Making transition to {} for {}", transition, issueKey);
+    JiraTransition.Item t = getTransitionByName(issueKey, transition);
     if (t == null) {
-      throw new InvalidTransitionException("Action " + transition
-        + " not executable on issue " + issueKey);
+      throw new InvalidTransitionException(
+          "Action " + transition + " not executable on issue " + issueKey);
     }
-    TransitionInput input;
-    input = new TransitionInput(t.getId());
-    log.debug("Setting transition input to: " + input.toString());
-    client.getIssueClient().transition(getIssue(issueKey), input).claim();
-    return true;
+    log.debug("Transition issue {} to '{}' ({})", issueKey, transition,
+        t.getId());
+    return apiBuilder.getIssue().doPost("/" + issueKey + "/transitions",
+        gson.toJson(new JiraTransition(t)), HTTP_NO_CONTENT);
   }
 
   /**
    * @return Serverinformation of jira
    */
-  public ServerInfo sysInfo() throws RestClientException {
-    return client.getMetadataClient().getServerInfo().claim();
+  public JiraServerInfo sysInfo() throws IOException {
+    return apiBuilder.getServerInfo().doGet("", HTTP_OK);
   }
 
-  private Transition getTransitionByName(Iterable<Transition> transitions, String transition) {
-    Transition ret = null;
-    for (Transition t : transitions) {
+  /**
+   * @return List of all projects we have access to in jira
+   */
+  public JiraProject[] getProjects() throws IOException {
+    return apiBuilder.getProjects().doGet("", HTTP_OK);
+  }
+
+  private JiraTransition.Item getTransitionByName(String issueKey,
+      String transition) throws IOException {
+    for (JiraTransition.Item t : getTransitions(issueKey)) {
       if (transition.equals(t.getName())) {
-        ret = t;
-        break;
+        return t;
       }
     }
-    return ret;
+    return null;
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
index fc76fc0..2f8da02 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
@@ -14,17 +14,21 @@
 
 package com.googlesource.gerrit.plugins.its.jira;
 
-import com.atlassian.jira.rest.client.api.domain.Comment;
-import com.atlassian.jira.rest.client.api.domain.ServerInfo;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
+
+import com.googlesource.gerrit.plugins.its.base.its.InvalidTransitionException;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraProject;
+import com.googlesource.gerrit.plugins.its.jira.restapi.JiraServerInfo;
+
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.concurrent.Callable;
 
@@ -45,12 +49,16 @@
 
   @Inject
   public JiraItsFacade(@PluginName String pluginName,
-                       @GerritServerConfig Config cfg) {
+      @GerritServerConfig Config cfg) {
     this.pluginName = pluginName;
     try {
       this.gerritConfig = cfg;
-      ServerInfo info = client().sysInfo();
-      log.info("Connected to JIRA at {}, reported version is {}", info.getBaseUri(), info.getVersion());
+      JiraServerInfo info = client().sysInfo();
+      log.info("Connected to JIRA at {}, reported version is {}",
+          info.getBaseUri(), info.getVersion());
+      for (JiraProject p : client().getProjects()) {
+        log.info("Found project: {} (key: {})", p.getName(), p.getKey());
+      }
     } catch (Exception ex) {
       log.warn("Jira is currently not available", ex);
     }
@@ -59,33 +67,35 @@
   @Override
   public String healthCheck(final Check check) throws IOException {
 
-    return execute(new Callable<String>(){
+    return execute(new Callable<String>() {
       @Override
       public String call() throws Exception {
-        if (check.equals(Check.ACCESS))
-          return healthCheckAccess();
-        else
-          return healthCheckSysinfo();
-      }});
+        if (check.equals(Check.ACCESS)) return healthCheckAccess();
+        return healthCheckSysinfo();
+      }
+    });
   }
 
   @Override
-  public void addComment(final String issueKey, final String comment) throws IOException {
+  public void addComment(final String issueKey, final String comment)
+      throws IOException {
 
-    execute(new Callable<String>(){
+    execute(new Callable<String>() {
       @Override
       public String call() throws Exception {
         log.debug("Adding comment {} to issue {}", comment, issueKey);
-        client().addComment(issueKey, Comment.valueOf(comment));
+        client().addComment(issueKey, comment);
         log.debug("Added comment {} to issue {}", comment, issueKey);
         return issueKey;
-      }});
+      }
+    });
   }
 
   @Override
-  public void addRelatedLink(final String issueKey, final URL relatedUrl, String description)
-      throws IOException {
-    addComment(issueKey, "Related URL: " + createLinkForWebui(relatedUrl.toExternalForm(), description));
+  public void addRelatedLink(final String issueKey, final URL relatedUrl,
+      String description) throws IOException {
+    addComment(issueKey, "Related URL: "
+        + createLinkForWebui(relatedUrl.toExternalForm(), description));
   }
 
   @Override
@@ -98,12 +108,14 @@
         log.debug("Performing action {} on issue {}", actionName, issueKey);
         doPerformAction(issueKey, actionName);
         return issueKey;
-      }});
+      }
+    });
   }
 
   private void doPerformAction(final String issueKey, final String actionName)
-      throws IOException {
-    log.debug("Trying to perform action: " + actionName + " on issue " + issueKey);
+      throws IOException, InvalidTransitionException {
+    log.debug(
+        "Trying to perform action: " + actionName + " on issue " + issueKey);
     boolean ret = client().doTransition(issueKey, actionName);
     if (ret) {
       log.debug("Action " + actionName + " successful on Issue " + issueKey);
@@ -118,54 +130,47 @@
       @Override
       public Boolean call() throws Exception {
         return client().issueExists(issueKey);
-      }});
+      }
+    });
   }
 
-  private JiraClient client() throws IOException {
+  private JiraClient client() throws MalformedURLException {
     if (client == null) {
-      try {
-        log.debug("Connecting to jira at {}", getUrl());
-        client = new JiraClient(getUrl(), getUsername(), getPassword());
-        log.debug("Authenticating as User {}", getUsername());
-      } catch (Exception e) {
-        log.info("Unable to connect to " + getUrl() + " as "
-          + getUsername());
-        throw new IOException(e);
-      }
+      log.debug("Connecting to jira at {}", getUrl());
+      client = new JiraClient(getUrl(), getUsername(), getPassword());
+      log.debug("Authenticating as User {}", getUsername());
     }
     return client;
   }
 
   private <P> P execute(Callable<P> function) throws IOException {
     int attempt = 0;
-    while(true) {
+    while (true) {
       try {
         return function.call();
       } catch (Exception ex) {
         if (isRecoverable(ex) && ++attempt < MAX_ATTEMPTS) {
-          log.debug("Call failed - retrying, attempt {} of {}", attempt, MAX_ATTEMPTS);
+          log.debug("Call failed - retrying, attempt {} of {}", attempt,
+              MAX_ATTEMPTS);
           continue;
         }
-        if (ex instanceof IOException)
-          throw ((IOException)ex);
-        else
-          throw new IOException(ex);
+        if (ex instanceof IOException) throw ((IOException) ex);
+        throw new IOException(ex);
       }
     }
   }
+
   private boolean isRecoverable(Exception ex) {
     String className = ex.getClass().getName();
     return className.startsWith("java.net");
   }
 
   private String getPassword() {
-    return gerritConfig.getString(pluginName, null,
-      GERRIT_CONFIG_PASSWORD);
+    return gerritConfig.getString(pluginName, null, GERRIT_CONFIG_PASSWORD);
   }
 
   private String getUsername() {
-    return gerritConfig.getString(pluginName, null,
-      GERRIT_CONFIG_USERNAME);
+    return gerritConfig.getString(pluginName, null, GERRIT_CONFIG_USERNAME);
   }
 
   private String getUrl() {
@@ -179,14 +184,18 @@
 
   private String healthCheckAccess() throws IOException {
     client().sysInfo();
-    final String result = "{\"status\"=\"ok\",\"username\"=\"" + getUsername() + "\"}";
+    final String result =
+        "{\"status\"=\"ok\",\"username\"=\"" + getUsername() + "\"}";
     log.debug("Healtheck on access result: {}", result);
     return result;
   }
 
   private String healthCheckSysinfo() throws IOException {
-    ServerInfo info = client().sysInfo();
-    final String result = "{\"status\"=\"ok\",\"system\"=\"Jira\",\"version\"=\""+info.getVersion()+"\",\"url\"=\""+getUrl()+"\",\"build\"=\""+info.getBuildNumber()+"\"}";
+    JiraServerInfo info = client().sysInfo();
+    final String result =
+        "{\"status\"=\"ok\",\"system\"=\"Jira\",\"version\"=\""
+            + info.getVersion() + "\",\"url\"=\"" + getUrl() + "\",\"build\"=\""
+            + info.getBuildNumber() + "\"}";
     log.debug("Healtheck on sysinfo result: {}", result);
     return result;
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraSession.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraSession.java
deleted file mode 100644
index 2609ddf..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraSession.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.its.jira;
-
-public class JiraSession {
-
-  private final String username;
-  private final String token;
-
-  public JiraSession(final String username, final String loginToken) {
-    super();
-    this.username = username;
-    this.token = loginToken;
-  }
-
-  public String getUsername() {
-    return username;
-  }
-
-  public String getToken() {
-    return token;
-  }
-
-  public String toString() {
-    return "username="+username+", token="+token;
-  }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java
new file mode 100644
index 0000000..e3e2f0e
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraComment.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+public class JiraComment {
+
+  final String body;
+
+  public JiraComment(String body) {
+    this.body = body;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssue.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssue.java
new file mode 100644
index 0000000..8a22098
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraIssue.java
@@ -0,0 +1,20 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+public class JiraIssue {
+  String id;
+  String key;
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraProject.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraProject.java
new file mode 100644
index 0000000..d244cb4
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraProject.java
@@ -0,0 +1,34 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+public class JiraProject {
+
+  String id;
+  String key;
+  String name;
+
+  public String getId() {
+    return id;
+  }
+
+  public String getKey() {
+    return key;
+  }
+
+  public String getName() {
+    return name;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApi.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApi.java
new file mode 100644
index 0000000..581f40b
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApi.java
@@ -0,0 +1,161 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+import com.google.gson.Gson;
+
+import java.util.Base64;
+import org.apache.commons.lang.ArrayUtils;
+import org.eclipse.jgit.util.HttpSupport;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.URL;
+
+/**
+ * Jira Rest Client.
+ */
+public class JiraRestApi<T> {
+  private static final String BASE_PREFIX = "/rest/api/2";
+  private final URL baseUrl;
+  private final String auth;
+  private final Gson gson;
+
+  private final Class<T> classOfT;
+  private final String classPrefix;
+  private T data;
+  private int responseCode;
+
+  /**
+   * @param url jira url
+   * @param user username of the jira user
+   * @param pass password of the jira user
+   */
+  JiraRestApi(URL url, String user, String pass, Class<T> classOfT,
+      String classPrefix) {
+    String auth = user + ":" + pass;
+    this.auth = new String(Base64.getEncoder().encodeToString(auth.getBytes()));
+    this.baseUrl = url;
+    this.gson = new Gson();
+    this.classOfT = classOfT;
+    this.classPrefix = classPrefix;
+  }
+
+  public int getResponseCode() {
+    return responseCode;
+  }
+
+  /**
+   * Do a simple GET request. Object of type 'T' is returned containing the
+   * parsed JSON data
+   *
+   * @param passCode HTTP response code required to mark this GET as success
+   * @param failCodes HTTP response codes allowed and not fail on unexcepted
+   *        response
+   * @throws IOException generated if unexpected failCode is returned
+   */
+  public T doGet(String spec, int passCode, int[] failCodes)
+      throws IOException {
+    HttpURLConnection conn = prepHttpConnection(spec, false);
+    try {
+      if (validateResponse(conn, passCode, failCodes)) {
+        readIncomingData(conn);
+      }
+      return data;
+    } finally {
+      conn.disconnect();
+    }
+  }
+
+  public T doGet(String spec, int passCode) throws IOException {
+    return doGet(spec, passCode, null);
+  }
+
+  /**
+   * Do a simple POST request.
+   */
+  public boolean doPost(String spec, String jsonInput, int passCode)
+      throws IOException {
+    HttpURLConnection conn = prepHttpConnection(spec, true);
+    try {
+      writePostData(jsonInput, conn);
+      return validateResponse(conn, passCode, null);
+    } finally {
+      conn.disconnect();
+    }
+  }
+
+  private HttpURLConnection prepHttpConnection(String spec,
+      boolean isPostRequest) throws IOException {
+    URL url = new URL(baseUrl, BASE_PREFIX + classPrefix + spec);
+    ProxySelector proxySelector = ProxySelector.getDefault();
+    Proxy proxy = HttpSupport.proxyFor(proxySelector, url);
+    HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
+    conn.setRequestProperty("Authorization", "Basic " + auth);
+    conn.setRequestProperty("Content-Type", "application/json");
+    if (isPostRequest) {
+      conn.setRequestMethod("POST");
+      conn.setDoOutput(true);
+    } else {
+      conn.setRequestMethod("GET");
+    }
+    return conn;
+  }
+
+  /**
+   * Write the Read the returned data from the HTTP connection.
+   */
+  private void writePostData(String postData, HttpURLConnection conn)
+      throws IOException {
+    if (postData != null) {
+      try (OutputStream os = conn.getOutputStream()) {
+        os.write(postData.getBytes());
+        os.flush();
+      }
+    }
+  }
+
+  /**
+   * Read the returned data from the HTTP connection.
+   */
+  private void readIncomingData(HttpURLConnection conn) throws IOException {
+    try (InputStreamReader isr = new InputStreamReader(conn.getInputStream())) {
+      data = gson.fromJson(isr, classOfT);
+    }
+  }
+
+  /**
+   * Checks if the connection returned one of the provides pass or fail Codes.
+   * If not, an IOException exception is thrown. If it was part of the list,
+   * then the actual response code is returned. returns true if valid response
+   * is returned, otherwise false
+   */
+  private boolean validateResponse(HttpURLConnection conn, int passCode,
+      int[] failCodes) throws IOException {
+    responseCode = conn.getResponseCode();
+    if (responseCode == passCode) {
+      return true;
+    }
+    if ((failCodes == null)
+        || (!ArrayUtils.contains(failCodes, responseCode))) {
+      throw new IOException("Request failed");
+    }
+    return false;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java
new file mode 100644
index 0000000..54ce637
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraRestApiProvider.java
@@ -0,0 +1,33 @@
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class JiraRestApiProvider {
+  private final URL url;
+  private final String user;
+  private final String pass;
+
+  public JiraRestApiProvider(String url, String user, String pass)
+      throws MalformedURLException {
+    this.url = new URL(url);
+    this.user = user;
+    this.pass = pass;
+  }
+
+  public <T> JiraRestApi<T> get(Class<T> classOfT, String classPrefix) {
+    return new JiraRestApi<>(url, user, pass, classOfT, classPrefix);
+  }
+
+  public JiraRestApi<JiraIssue> getIssue() {
+    return get(JiraIssue.class, "/issue");
+  }
+
+  public JiraRestApi<JiraServerInfo> getServerInfo() {
+    return get(JiraServerInfo.class, "/serverInfo");
+  }
+
+  public JiraRestApi<JiraProject[]> getProjects() {
+    return get(JiraProject[].class, "/project");
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraServerInfo.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraServerInfo.java
new file mode 100644
index 0000000..9b2fe79
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraServerInfo.java
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+public class JiraServerInfo {
+
+  String baseUrl;
+  String version;
+  String deploymentType;
+  String buildNumber;
+  String buildDate;
+  String serverTime;
+  String scmInfo;
+  String serverTitle;
+
+  public String getVersion() {
+    return version;
+  }
+
+  public String getBuildNumber() {
+    return buildNumber;
+  }
+
+  public String getBaseUri() {
+    return baseUrl;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraTransition.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraTransition.java
new file mode 100644
index 0000000..4bbad2c
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/restapi/JiraTransition.java
@@ -0,0 +1,41 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.its.jira.restapi;
+
+public class JiraTransition {
+
+  // 'Get Transactions' require a list of items
+  public Item[] transitions;
+
+  // 'Do Transaction' require a single item
+  Item transition;
+
+  public JiraTransition(Item transition) {
+    this.transition = transition;
+  }
+
+  public static class Item {
+    String name;
+    String id;
+
+    public String getName() {
+      return name;
+    }
+
+    public String getId() {
+      return id;
+    }
+  }
+}
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 20e452f..1235321 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -7,17 +7,6 @@
 [plugins/its-base](https://gerrit-review.googlesource.com/#/admin/projects/plugins/its-base)
 to the `plugins` directory of Gerrit's source tree.
 
-Put the external dependency Bazel build file into the Gerrit /plugins directory,
-replacing the existing empty one.
-
-```
-  cd gerrit/plugins
-  rm external_plugin_deps.bzl
-  cd @PLUGIN@
-  cp external_plugin_deps.bzl ../
-  cd ../../
-```
-
 Then issue
 
 ```