| // 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 static java.nio.charset.StandardCharsets.UTF_8; |
| |
| import com.google.gson.Gson; |
| import com.google.inject.Inject; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.OutputStream; |
| import java.net.HttpURLConnection; |
| import java.net.ProxySelector; |
| import java.util.Base64; |
| import org.apache.commons.lang3.ArrayUtils; |
| |
| /** Jira Rest Client. */ |
| public class JiraRestApi<T> { |
| |
| private static final String BASE_PREFIX = "rest/api/2"; |
| |
| private final JiraURL baseUrl; |
| private final String auth; |
| private final Gson gson; |
| |
| private final Class<T> classOfT; |
| private T data; |
| private int responseCode; |
| |
| /** |
| * Create a new Jira REST API client |
| * |
| * @param url jira url |
| * @param user username of the jira user |
| * @param pass password of the jira user |
| * @param classOfT class type of the object requested |
| * @param classPrefix prefix for the rest api request |
| */ |
| @Inject |
| public JiraRestApi(JiraURL url, String user, String pass, Class<T> classOfT, String classPrefix) { |
| this.auth = encode(user, pass); |
| this.baseUrl = url == null ? url : url.resolveUrl(BASE_PREFIX, classPrefix, "/"); |
| this.gson = new Gson(); |
| this.classOfT = classOfT; |
| } |
| |
| private static String encode(String user, String pass) { |
| return Base64.getEncoder().encodeToString((user + ":" + pass).getBytes()); |
| } |
| |
| 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 unexpected response |
| * @throws IOException generated if unexpected failCode is returned |
| */ |
| public T doGet(String spec, int passCode, int[] failCodes) throws IOException { |
| HttpURLConnection conn = openConnection(spec, "GET", false); |
| try { |
| if (validateResponse(conn, new int[] {passCode}, failCodes)) { |
| readIncomingData(conn); |
| } |
| return data; |
| } finally { |
| conn.disconnect(); |
| } |
| } |
| |
| public T doGet(String spec, int passCode) throws IOException { |
| return doGet(spec, passCode, null); |
| } |
| |
| JiraURL getBaseUrl() { |
| return baseUrl; |
| } |
| |
| /** Do a simple POST request. */ |
| public boolean doPost(String spec, String jsonInput, int passCode) throws IOException { |
| return sendPayload("POST", spec, jsonInput, passCode); |
| } |
| |
| /** Do a simple PUT request. */ |
| public boolean doPut(String spec, String jsonInput, int passCode) throws IOException { |
| return sendPayload("PUT", spec, jsonInput, passCode); |
| } |
| |
| /** Open an HTTP connection with the Jira's endpoint URL. */ |
| public HttpURLConnection openConnection(String spec, String method, boolean withPayload) |
| throws IOException { |
| JiraURL url = baseUrl.withSpec(spec); |
| ProxySelector proxySelector = ProxySelector.getDefault(); |
| HttpURLConnection conn = url.openConnection(proxySelector); |
| conn.setRequestProperty("Authorization", "Basic " + auth); |
| conn.setRequestProperty("Content-Type", "application/json"); |
| |
| conn.setRequestMethod(method.toUpperCase()); |
| if (withPayload) { |
| conn.setDoOutput(true); |
| } |
| return conn; |
| } |
| |
| private boolean sendPayload(String method, String spec, String jsonInput, int passCode) |
| throws IOException { |
| return sendPayload(method, spec, jsonInput, new int[] {passCode}); |
| } |
| |
| public boolean sendPayload(String method, String spec, String jsonInput, int[] passCodes) |
| throws IOException { |
| HttpURLConnection conn = openConnection(spec, method, true); |
| try { |
| writeBodyData(jsonInput, conn); |
| return validateResponse(conn, passCodes, null); |
| } finally { |
| conn.disconnect(); |
| } |
| } |
| |
| /** Write the data to the HTTP connection. */ |
| private void writeBodyData(String data, HttpURLConnection conn) throws IOException { |
| if (data != null) { |
| try (OutputStream os = conn.getOutputStream()) { |
| os.write(data.getBytes(UTF_8)); |
| 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[] passCodes, int[] failCodes) |
| throws IOException { |
| responseCode = conn.getResponseCode(); |
| if (ArrayUtils.contains(passCodes, responseCode)) { |
| return true; |
| } |
| if ((failCodes == null) || (!ArrayUtils.contains(failCodes, responseCode))) { |
| throw new IOException( |
| "Request failed: " |
| + conn.getURL() |
| + " - " |
| + conn.getResponseCode() |
| + " - " |
| + conn.getResponseMessage()); |
| } |
| return false; |
| } |
| } |