All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.finbourne.workflow.ApiClient Maven / Gradle / Ivy

There is a newer version: 2.0.166
Show newest version
/*
 * FINBOURNE Workflow API
 *
 * Contact: [email protected]
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

package com.finbourne.workflow;

import okhttp3.*;
import okhttp3.internal.http.HttpMethod;
import okhttp3.internal.tls.OkHostnameVerifier;
import okhttp3.logging.HttpLoggingInterceptor;
import okhttp3.logging.HttpLoggingInterceptor.Level;
import okhttp3.OkHttpClient.Builder;
import okio.Buffer;
import okio.BufferedSink;
import okio.Okio;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.apache.oltu.oauth2.common.message.types.GrantType;

import javax.net.ssl.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.finbourne.workflow.auth.Authentication;
import com.finbourne.workflow.auth.HttpBasicAuth;
import com.finbourne.workflow.auth.HttpBearerAuth;
import com.finbourne.workflow.auth.ApiKeyAuth;
import com.finbourne.workflow.auth.OAuth;
import com.finbourne.workflow.auth.RetryingOAuth;
import com.finbourne.workflow.auth.OAuthFlow;
import com.finbourne.workflow.extensions.ConfigurationOptions;
import com.finbourne.workflow.extensions.RateLimitRetryInterceptor;

/**
 * 

ApiClient class.

*/ public class ApiClient { private String basePath = "https://fbn-prd.lusid.com/workflow"; protected List servers = new ArrayList(Arrays.asList( new ServerConfiguration( "https://fbn-prd.lusid.com/workflow", "No description provided", new HashMap() ) )); protected Integer serverIndex = 0; protected Map serverVariables = null; private boolean debugging = false; private Map defaultHeaderMap = new HashMap(); private Map defaultCookieMap = new HashMap(); private String tempFolderPath = null; private Map authentications; private DateFormat dateFormat; private DateFormat datetimeFormat; private boolean lenientDatetimeFormat; private int dateLength; private InputStream sslCaCert; private boolean verifyingSsl; private KeyManager[] keyManagers; private OkHttpClient httpClient; private JSON json; private HttpLoggingInterceptor loggingInterceptor; /** * Basic constructor for ApiClient */ public ApiClient() { init(); initHttpClient(); // Setup authentications (key: authentication name, value: authentication). authentications.put("oauth2", new OAuth()); // Prevent the authentications from being modified. authentications = Collections.unmodifiableMap(authentications); } /** * Basic constructor with custom OkHttpClient * * @param client a {@link okhttp3.OkHttpClient} object */ public ApiClient(OkHttpClient client) { init(); httpClient = client; // Setup authentications (key: authentication name, value: authentication). authentications.put("oauth2", new OAuth()); // Prevent the authentications from being modified. authentications = Collections.unmodifiableMap(authentications); } /** * Constructor for ApiClient to support access token retry on 401/403 configured with client ID * * @param clientId client ID */ public ApiClient(String clientId) { this(clientId, null, null); } /** * Constructor for ApiClient to support access token retry on 401/403 configured with client ID and additional parameters * * @param clientId client ID * @param parameters a {@link java.util.Map} of parameters */ public ApiClient(String clientId, Map parameters) { this(clientId, null, parameters); } /** * Constructor for ApiClient to support access token retry on 401/403 configured with client ID, secret, and additional parameters * * @param clientId client ID * @param clientSecret client secret * @param parameters a {@link java.util.Map} of parameters */ public ApiClient(String clientId, String clientSecret, Map parameters) { this(null, clientId, clientSecret, parameters); } /** * Constructor for ApiClient to support access token retry on 401/403 configured with base path, client ID, secret, and additional parameters * * @param basePath base path * @param clientId client ID * @param clientSecret client secret * @param parameters a {@link java.util.Map} of parameters */ public ApiClient(String basePath, String clientId, String clientSecret, Map parameters) { init(); if (basePath != null) { this.basePath = basePath; } String tokenUrl = ""; if (!"".equals(tokenUrl) && !URI.create(tokenUrl).isAbsolute()) { URI uri = URI.create(getBasePath()); tokenUrl = uri.getScheme() + ":" + (uri.getAuthority() != null ? "//" + uri.getAuthority() : "") + tokenUrl; if (!URI.create(tokenUrl).isAbsolute()) { throw new IllegalArgumentException("OAuth2 token URL must be an absolute URL"); } } RetryingOAuth retryingOAuth = new RetryingOAuth(tokenUrl, clientId, OAuthFlow.IMPLICIT, clientSecret, parameters); authentications.put( "oauth2", retryingOAuth ); initHttpClient(Collections.singletonList(retryingOAuth)); // Setup authentications (key: authentication name, value: authentication). // Prevent the authentications from being modified. authentications = Collections.unmodifiableMap(authentications); } private void initHttpClient() { initHttpClient(Collections.emptyList()); } private void initHttpClient(List interceptors) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.addNetworkInterceptor(getProgressInterceptor()); for (Interceptor interceptor: interceptors) { builder.addInterceptor(interceptor); } httpClient = builder.build(); } private void init() { verifyingSsl = true; json = new JSON(); // Set default User-Agent. setUserAgent("OpenAPI-Generator/2.0.144/java"); authentications = new HashMap(); } /** * Get base path * * @return Base path */ public String getBasePath() { return basePath; } /** * Set base path * * @param basePath Base path of the URL (e.g https://fbn-prd.lusid.com/workflow * @return An instance of OkHttpClient */ public ApiClient setBasePath(String basePath) { this.basePath = basePath; this.serverIndex = null; return this; } public List getServers() { return servers; } public ApiClient setServers(List servers) { this.servers = servers; return this; } public Integer getServerIndex() { return serverIndex; } public ApiClient setServerIndex(Integer serverIndex) { this.serverIndex = serverIndex; return this; } public Map getServerVariables() { return serverVariables; } public ApiClient setServerVariables(Map serverVariables) { this.serverVariables = serverVariables; return this; } /** * Get HTTP client * * @return An instance of OkHttpClient */ public OkHttpClient getHttpClient() { return httpClient; } /** * Set HTTP client, which must never be null. * * @param newHttpClient An instance of OkHttpClient * @return Api Client * @throws java.lang.NullPointerException when newHttpClient is null */ public ApiClient setHttpClient(OkHttpClient newHttpClient) { this.httpClient = Objects.requireNonNull(newHttpClient, "HttpClient must not be null!"); return this; } /** * Get JSON * * @return JSON object */ public JSON getJSON() { return json; } /** * Set JSON * * @param json JSON object * @return Api client */ public ApiClient setJSON(JSON json) { this.json = json; return this; } /** * True if isVerifyingSsl flag is on * * @return True if isVerifySsl flag is on */ public boolean isVerifyingSsl() { return verifyingSsl; } /** * Configure whether to verify certificate and hostname when making https requests. * Default to true. * NOTE: Do NOT set to false in production code, otherwise you would face multiple types of cryptographic attacks. * * @param verifyingSsl True to verify TLS/SSL connection * @return ApiClient */ public ApiClient setVerifyingSsl(boolean verifyingSsl) { this.verifyingSsl = verifyingSsl; applySslSettings(); return this; } /** * Get SSL CA cert. * * @return Input stream to the SSL CA cert */ public InputStream getSslCaCert() { return sslCaCert; } /** * Configure the CA certificate to be trusted when making https requests. * Use null to reset to default. * * @param sslCaCert input stream for SSL CA cert * @return ApiClient */ public ApiClient setSslCaCert(InputStream sslCaCert) { this.sslCaCert = sslCaCert; applySslSettings(); return this; } /** *

Getter for the field keyManagers.

* * @return an array of {@link javax.net.ssl.KeyManager} objects */ public KeyManager[] getKeyManagers() { return keyManagers; } /** * Configure client keys to use for authorization in an SSL session. * Use null to reset to default. * * @param managers The KeyManagers to use * @return ApiClient */ public ApiClient setKeyManagers(KeyManager[] managers) { this.keyManagers = managers; applySslSettings(); return this; } /** *

Getter for the field dateFormat.

* * @return a {@link java.text.DateFormat} object */ public DateFormat getDateFormat() { return dateFormat; } /** *

Setter for the field dateFormat.

* * @param dateFormat a {@link java.text.DateFormat} object * @return a {@link com.finbourne.workflow.ApiClient} object */ public ApiClient setDateFormat(DateFormat dateFormat) { JSON.setDateFormat(dateFormat); return this; } /** *

Set SqlDateFormat.

* * @param dateFormat a {@link java.text.DateFormat} object * @return a {@link com.finbourne.workflow.ApiClient} object */ public ApiClient setSqlDateFormat(DateFormat dateFormat) { JSON.setSqlDateFormat(dateFormat); return this; } /** *

Set OffsetDateTimeFormat.

* * @param dateFormat a {@link java.time.format.DateTimeFormatter} object * @return a {@link com.finbourne.workflow.ApiClient} object */ public ApiClient setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { JSON.setOffsetDateTimeFormat(dateFormat); return this; } /** *

Set LocalDateFormat.

* * @param dateFormat a {@link java.time.format.DateTimeFormatter} object * @return a {@link com.finbourne.workflow.ApiClient} object */ public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { JSON.setLocalDateFormat(dateFormat); return this; } /** *

Set LenientOnJson.

* * @param lenientOnJson a boolean * @return a {@link com.finbourne.workflow.ApiClient} object */ public ApiClient setLenientOnJson(boolean lenientOnJson) { JSON.setLenientOnJson(lenientOnJson); return this; } /** * Get authentications (key: authentication name, value: authentication). * * @return Map of authentication objects */ public Map getAuthentications() { return authentications; } /** * Get authentication for the given name. * * @param authName The authentication name * @return The authentication, null if not found */ public Authentication getAuthentication(String authName) { return authentications.get(authName); } /** * Helper method to set username for the first HTTP basic authentication. * * @param username Username */ public void setUsername(String username) { for (Authentication auth : authentications.values()) { if (auth instanceof HttpBasicAuth) { ((HttpBasicAuth) auth).setUsername(username); return; } } throw new RuntimeException("No HTTP basic authentication configured!"); } /** * Helper method to set password for the first HTTP basic authentication. * * @param password Password */ public void setPassword(String password) { for (Authentication auth : authentications.values()) { if (auth instanceof HttpBasicAuth) { ((HttpBasicAuth) auth).setPassword(password); return; } } throw new RuntimeException("No HTTP basic authentication configured!"); } /** * Helper method to set API key value for the first API key authentication. * * @param apiKey API key */ public void setApiKey(String apiKey) { for (Authentication auth : authentications.values()) { if (auth instanceof ApiKeyAuth) { ((ApiKeyAuth) auth).setApiKey(apiKey); return; } } throw new RuntimeException("No API key authentication configured!"); } /** * Helper method to set API key prefix for the first API key authentication. * * @param apiKeyPrefix API key prefix */ public void setApiKeyPrefix(String apiKeyPrefix) { for (Authentication auth : authentications.values()) { if (auth instanceof ApiKeyAuth) { ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); return; } } throw new RuntimeException("No API key authentication configured!"); } /** * Helper method to set access token for the first OAuth2 authentication. * * @param accessToken Access token */ public void setAccessToken(String accessToken) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).setAccessToken(accessToken); return; } } throw new RuntimeException("No OAuth2 authentication configured!"); } /** * Helper method to set credentials for AWSV4 Signature * * @param accessKey Access Key * @param secretKey Secret Key * @param region Region * @param service Service to access to */ public void setAWS4Configuration(String accessKey, String secretKey, String region, String service) { throw new RuntimeException("No AWS4 authentication configured!"); } /** * Set the User-Agent header's value (by adding to the default header map). * * @param userAgent HTTP request's user agent * @return ApiClient */ public ApiClient setUserAgent(String userAgent) { addDefaultHeader("User-Agent", userAgent); return this; } /** * Add a default header. * * @param key The header's key * @param value The header's value * @return ApiClient */ public ApiClient addDefaultHeader(String key, String value) { defaultHeaderMap.put(key, value); return this; } /** * Add a default cookie. * * @param key The cookie's key * @param value The cookie's value * @return ApiClient */ public ApiClient addDefaultCookie(String key, String value) { defaultCookieMap.put(key, value); return this; } /** * Check that whether debugging is enabled for this API client. * * @return True if debugging is enabled, false otherwise. */ public boolean isDebugging() { return debugging; } /** * Enable/disable debugging for this API client. * * @param debugging To enable (true) or disable (false) debugging * @return ApiClient */ public ApiClient setDebugging(boolean debugging) { if (debugging != this.debugging) { if (debugging) { loggingInterceptor = new HttpLoggingInterceptor(); loggingInterceptor.setLevel(Level.BODY); httpClient = httpClient.newBuilder().addInterceptor(loggingInterceptor).build(); } else { final OkHttpClient.Builder builder = httpClient.newBuilder(); builder.interceptors().remove(loggingInterceptor); httpClient = builder.build(); loggingInterceptor = null; } } this.debugging = debugging; return this; } /** * The path of temporary folder used to store downloaded files from endpoints * with file response. The default value is null, i.e. using * the system's default temporary folder. * * @see createTempFile * @return Temporary folder path */ public String getTempFolderPath() { return tempFolderPath; } /** * Set the temporary folder path (for downloading files) * * @param tempFolderPath Temporary folder path * @return ApiClient */ public ApiClient setTempFolderPath(String tempFolderPath) { this.tempFolderPath = tempFolderPath; return this; } /** * Get connection timeout (in milliseconds). * * @return Timeout in milliseconds */ public int getConnectTimeout() { return httpClient.connectTimeoutMillis(); } /** * Sets the connect timeout (in milliseconds). * A value of 0 means no timeout, otherwise values must be between 1 and * {@link java.lang.Integer#MAX_VALUE}. * * @param connectionTimeout connection timeout in milliseconds * @return Api client */ public ApiClient setConnectTimeout(int connectionTimeout) { httpClient = httpClient.newBuilder().connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS).build(); return this; } /** * Get read timeout (in milliseconds). * * @return Timeout in milliseconds */ public int getReadTimeout() { return httpClient.readTimeoutMillis(); } /** * Sets the read timeout (in milliseconds). * A value of 0 means no timeout, otherwise values must be between 1 and * {@link java.lang.Integer#MAX_VALUE}. * * @param readTimeout read timeout in milliseconds * @return Api client */ public ApiClient setReadTimeout(int readTimeout) { httpClient = httpClient.newBuilder().readTimeout(readTimeout, TimeUnit.MILLISECONDS).build(); return this; } /** * Get write timeout (in milliseconds). * * @return Timeout in milliseconds */ public int getWriteTimeout() { return httpClient.writeTimeoutMillis(); } /** * Sets the write timeout (in milliseconds). * A value of 0 means no timeout, otherwise values must be between 1 and * {@link java.lang.Integer#MAX_VALUE}. * * @param writeTimeout connection timeout in milliseconds * @return Api client */ public ApiClient setWriteTimeout(int writeTimeout) { httpClient = httpClient.newBuilder().writeTimeout(writeTimeout, TimeUnit.MILLISECONDS).build(); return this; } /** * Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) * * @return Token request builder */ public TokenRequestBuilder getTokenEndPoint() { for (Authentication apiAuth : authentications.values()) { if (apiAuth instanceof RetryingOAuth) { RetryingOAuth retryingOAuth = (RetryingOAuth) apiAuth; return retryingOAuth.getTokenRequestBuilder(); } } return null; } /** * Format the given parameter object into string. * * @param param Parameter * @return String representation of the parameter */ public String parameterToString(Object param) { if (param == null) { return ""; } else if (param instanceof Date || param instanceof OffsetDateTime || param instanceof LocalDate) { //Serialize to json string and remove the " enclosing characters String jsonStr = JSON.serialize(param); return jsonStr.substring(1, jsonStr.length() - 1); } else if (param instanceof Collection) { StringBuilder b = new StringBuilder(); for (Object o : (Collection) param) { if (b.length() > 0) { b.append(","); } b.append(o); } return b.toString(); } else { return String.valueOf(param); } } /** * Formats the specified query parameter to a list containing a single {@code Pair} object. * * Note that {@code value} must not be a collection. * * @param name The name of the parameter. * @param value The value of the parameter. * @return A list containing a single {@code Pair} object. */ public List parameterToPair(String name, Object value) { List params = new ArrayList(); // preconditions if (name == null || name.isEmpty() || value == null || value instanceof Collection) { return params; } params.add(new Pair(name, parameterToString(value))); return params; } /** * Formats the specified collection query parameters to a list of {@code Pair} objects. * * Note that the values of each of the returned Pair objects are percent-encoded. * * @param collectionFormat The collection format of the parameter. * @param name The name of the parameter. * @param value The value of the parameter. * @return A list of {@code Pair} objects. */ public List parameterToPairs(String collectionFormat, String name, Collection value) { List params = new ArrayList(); // preconditions if (name == null || name.isEmpty() || value == null || value.isEmpty()) { return params; } // create the params based on the collection format if ("multi".equals(collectionFormat)) { for (Object item : value) { params.add(new Pair(name, escapeString(parameterToString(item)))); } return params; } // collectionFormat is assumed to be "csv" by default String delimiter = ","; // escape all delimiters except commas, which are URI reserved // characters if ("ssv".equals(collectionFormat)) { delimiter = escapeString(" "); } else if ("tsv".equals(collectionFormat)) { delimiter = escapeString("\t"); } else if ("pipes".equals(collectionFormat)) { delimiter = escapeString("|"); } StringBuilder sb = new StringBuilder(); for (Object item : value) { sb.append(delimiter); sb.append(escapeString(parameterToString(item))); } params.add(new Pair(name, sb.substring(delimiter.length()))); return params; } /** * Formats the specified collection path parameter to a string value. * * @param collectionFormat The collection format of the parameter. * @param value The value of the parameter. * @return String representation of the parameter */ public String collectionPathParameterToString(String collectionFormat, Collection value) { // create the value based on the collection format if ("multi".equals(collectionFormat)) { // not valid for path params return parameterToString(value); } // collectionFormat is assumed to be "csv" by default String delimiter = ","; if ("ssv".equals(collectionFormat)) { delimiter = " "; } else if ("tsv".equals(collectionFormat)) { delimiter = "\t"; } else if ("pipes".equals(collectionFormat)) { delimiter = "|"; } StringBuilder sb = new StringBuilder() ; for (Object item : value) { sb.append(delimiter); sb.append(parameterToString(item)); } return sb.substring(delimiter.length()); } /** * Sanitize filename by removing path. * e.g. ../../sun.gif becomes sun.gif * * @param filename The filename to be sanitized * @return The sanitized filename */ public String sanitizeFilename(String filename) { return filename.replaceAll(".*[/\\\\]", ""); } /** * Check if the given MIME is a JSON MIME. * JSON MIME examples: * application/json * application/json; charset=UTF8 * APPLICATION/JSON * application/vnd.company+json * "* / *" is also default to JSON * @param mime MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ public boolean isJsonMime(String mime) { String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"; return mime != null && (mime.matches(jsonMime) || mime.equals("*/*")); } /** * Select the Accept header's value from the given accepts array: * if JSON exists in the given array, use it; * otherwise use all of them (joining into a string) * * @param accepts The accepts array to select from * @return The Accept header to use. If the given array is empty, * null will be returned (not to set the Accept header explicitly). */ public String selectHeaderAccept(String[] accepts) { if (accepts.length == 0) { return null; } for (String accept : accepts) { if (isJsonMime(accept)) { return accept; } } return StringUtil.join(accepts, ","); } /** * Select the Content-Type header's value from the given array: * if JSON exists in the given array, use it; * otherwise use the first one of the array. * * @param contentTypes The Content-Type array to select from * @return The Content-Type header to use. If the given array is empty, * returns null. If it matches "any", JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { if (contentTypes.length == 0) { return null; } if (contentTypes[0].equals("*/*")) { return "application/json"; } for (String contentType : contentTypes) { if (isJsonMime(contentType)) { return contentType; } } return contentTypes[0]; } /** * Escape the given string to be used as URL query value. * * @param str String to be escaped * @return Escaped string */ public String escapeString(String str) { try { return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); } catch (UnsupportedEncodingException e) { return str; } } /** * Deserialize response body to Java object, according to the return type and * the Content-Type response header. * * @param Type * @param response HTTP response * @param returnType The type of the Java object * @return The deserialized Java object * @throws com.finbourne.workflow.ApiException If fail to deserialize response body, i.e. cannot read response body * or the Content-Type of the response is not supported. */ @SuppressWarnings("unchecked") public T deserialize(Response response, Type returnType) throws ApiException { if (response == null || returnType == null) { return null; } if ("byte[]".equals(returnType.toString())) { // Handle binary response (byte array). try { return (T) response.body().bytes(); } catch (IOException e) { throw new ApiException(e); } } else if (returnType.equals(File.class)) { // Handle file downloading. return (T) downloadFileFromResponse(response); } String respBody; try { if (response.body() != null) respBody = response.body().string(); else respBody = null; } catch (IOException e) { throw new ApiException(e); } if (respBody == null || "".equals(respBody)) { return null; } String contentType = response.headers().get("Content-Type"); if (contentType == null) { // ensuring a default content type contentType = "application/json"; } if (isJsonMime(contentType)) { return JSON.deserialize(respBody, returnType); } else if (returnType.equals(String.class)) { // Expecting string, return the raw response body. return (T) respBody; } else { throw new ApiException( "Content type \"" + contentType + "\" is not supported for type: " + returnType, response.code(), response.headers().toMultimap(), respBody); } } /** * Serialize the given Java object into request body according to the object's * class and the request Content-Type. * * @param obj The Java object * @param contentType The request Content-Type * @return The serialized request body * @throws com.finbourne.workflow.ApiException If fail to serialize the given object */ public RequestBody serialize(Object obj, String contentType) throws ApiException { if (obj instanceof byte[]) { // Binary (byte array) body parameter support. return RequestBody.create((byte[]) obj, MediaType.parse(contentType)); } else if (obj instanceof File) { // File body parameter support. return RequestBody.create((File) obj, MediaType.parse(contentType)); } else if ("text/plain".equals(contentType) && obj instanceof String) { return RequestBody.create((String) obj, MediaType.parse(contentType)); } else if (isJsonMime(contentType)) { String content; if (obj != null) { content = JSON.serialize(obj); } else { content = null; } return RequestBody.create(content, MediaType.parse(contentType)); } else if (obj instanceof String) { return RequestBody.create((String) obj, MediaType.parse(contentType)); } else { throw new ApiException("Content type \"" + contentType + "\" is not supported"); } } /** * Download file from the given response. * * @param response An instance of the Response object * @throws com.finbourne.workflow.ApiException If fail to read file content from response and write to disk * @return Downloaded file */ public File downloadFileFromResponse(Response response) throws ApiException { try { File file = prepareDownloadFile(response); BufferedSink sink = Okio.buffer(Okio.sink(file)); sink.writeAll(response.body().source()); sink.close(); return file; } catch (IOException e) { throw new ApiException(e); } } /** * Prepare file for download * * @param response An instance of the Response object * @return Prepared file for the download * @throws java.io.IOException If fail to prepare file for download */ public File prepareDownloadFile(Response response) throws IOException { String filename = null; String contentDisposition = response.header("Content-Disposition"); if (contentDisposition != null && !"".equals(contentDisposition)) { // Get filename from the Content-Disposition header. Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?"); Matcher matcher = pattern.matcher(contentDisposition); if (matcher.find()) { filename = sanitizeFilename(matcher.group(1)); } } String prefix = null; String suffix = null; if (filename == null) { prefix = "download-"; suffix = ""; } else { int pos = filename.lastIndexOf("."); if (pos == -1) { prefix = filename + "-"; } else { prefix = filename.substring(0, pos) + "-"; suffix = filename.substring(pos); } // Files.createTempFile requires the prefix to be at least three characters long if (prefix.length() < 3) prefix = "download-"; } if (tempFolderPath == null) return Files.createTempFile(prefix, suffix).toFile(); else return Files.createTempFile(Paths.get(tempFolderPath), prefix, suffix).toFile(); } /** * {@link #execute(Call, Type)} * * @param Type * @param call An instance of the Call object * @return ApiResponse<T> * @throws com.finbourne.workflow.ApiException If fail to execute the call */ public ApiResponse execute(Call call) throws ApiException { return execute(call, null); } /** * Execute HTTP call and deserialize the HTTP response body into the given return type. * * @param returnType The return type used to deserialize HTTP response body * @param The return type corresponding to (same with) returnType * @param call Call * @return ApiResponse object containing response status, headers and * data, which is a Java object deserialized from response body and would be null * when returnType is null. * @throws com.finbourne.workflow.ApiException If fail to execute the call */ public ApiResponse execute(Call call, Type returnType) throws ApiException { try { Response response = call.execute(); T data = handleResponse(response, returnType); return new ApiResponse(response.code(), response.headers().toMultimap(), data); } catch (IOException e) { throw new ApiException(e); } } /** * {@link #executeAsync(Call, Type, ApiCallback)} * * @param Type * @param call An instance of the Call object * @param callback ApiCallback<T> */ public void executeAsync(Call call, ApiCallback callback) { executeAsync(call, null, callback); } /** * Execute HTTP call asynchronously. * * @param Type * @param call The callback to be executed when the API call finishes * @param returnType Return type * @param callback ApiCallback * @see #execute(Call, Type) */ @SuppressWarnings("unchecked") public void executeAsync(Call call, final Type returnType, final ApiCallback callback) { call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { callback.onFailure(new ApiException(e), 0, null); } @Override public void onResponse(Call call, Response response) throws IOException { T result; try { result = (T) handleResponse(response, returnType); } catch (ApiException e) { callback.onFailure(e, response.code(), response.headers().toMultimap()); return; } catch (Exception e) { callback.onFailure(new ApiException(e), response.code(), response.headers().toMultimap()); return; } callback.onSuccess(result, response.code(), response.headers().toMultimap()); } }); } /** * Handle the given response, return the deserialized object when the response is successful. * * @param Type * @param response Response * @param returnType Return type * @return Type * @throws com.finbourne.workflow.ApiException If the response has an unsuccessful status code or * fail to deserialize the response body */ public T handleResponse(Response response, Type returnType) throws ApiException { if (response.isSuccessful()) { if (returnType == null || response.code() == 204) { // returning null if the returnType is not defined, // or the status code is 204 (No Content) if (response.body() != null) { try { response.body().close(); } catch (Exception e) { throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); } } return null; } else { return deserialize(response, returnType); } } else { String respBody = null; if (response.body() != null) { try { respBody = response.body().string(); } catch (IOException e) { throw new ApiException(response.message(), e, response.code(), response.headers().toMultimap()); } } throw new ApiException(response.message(), response.code(), response.headers().toMultimap(), respBody); } } /** * Build HTTP call with the given options. * * @param baseUrl The base URL * @param path The sub-path of the HTTP URL * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" * @param queryParams The query parameters * @param collectionQueryParams The collection query parameters * @param body The request body object * @param headerParams The header parameters * @param cookieParams The cookie parameters * @param formParams The form parameters * @param authNames The authentications to apply * @param callback Callback for upload/download progress * @return The HTTP call * @throws com.finbourne.workflow.ApiException If fail to serialize the request body object */ public Call buildCall(String baseUrl, String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback) throws ApiException { Request request = buildRequest(baseUrl, path, method, queryParams, collectionQueryParams, body, headerParams, cookieParams, formParams, authNames, callback); return httpClient.newCall(request); } public Call buildCall(String baseUrl, String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback, ConfigurationOptions opts) throws ApiException { Request request = buildRequest(baseUrl, path, method, queryParams, collectionQueryParams, body, headerParams, cookieParams, formParams, authNames, callback); if (opts == null || opts.noOptionsSet()) { return httpClient.newCall(request); } // these options are being set for a single request - do not modify the existing http client Builder clientBuilder = httpClient.newBuilder(); if (opts.getRateLimitRetries() != null) { clientBuilder.interceptors().removeIf(i -> (i instanceof RateLimitRetryInterceptor)); clientBuilder.addInterceptor(new RateLimitRetryInterceptor(opts.getRateLimitRetries())); } if (opts.getTotalTimeoutMs() != null) { clientBuilder.callTimeout(Duration.ofMillis(opts.getTotalTimeoutMs())); } if (opts.getConnectTimeoutMs() != null) { clientBuilder.connectTimeout(Duration.ofMillis(opts.getConnectTimeoutMs())); } if (opts.getReadTimeoutMs() != null) { clientBuilder.readTimeout(Duration.ofMillis(opts.getReadTimeoutMs())); } if (opts.getWriteTimeoutMs() != null) { clientBuilder.writeTimeout(Duration.ofMillis(opts.getWriteTimeoutMs())); } return clientBuilder.build().newCall(request); } /** * Build an HTTP request with the given options. * * @param baseUrl The base URL * @param path The sub-path of the HTTP URL * @param method The request method, one of "GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH" and "DELETE" * @param queryParams The query parameters * @param collectionQueryParams The collection query parameters * @param body The request body object * @param headerParams The header parameters * @param cookieParams The cookie parameters * @param formParams The form parameters * @param authNames The authentications to apply * @param callback Callback for upload/download progress * @return The HTTP request * @throws com.finbourne.workflow.ApiException If fail to serialize the request body object */ public Request buildRequest(String baseUrl, String path, String method, List queryParams, List collectionQueryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String[] authNames, ApiCallback callback) throws ApiException { // aggregate queryParams (non-collection) and collectionQueryParams into allQueryParams List allQueryParams = new ArrayList(queryParams); allQueryParams.addAll(collectionQueryParams); final String url = buildUrl(baseUrl, path, queryParams, collectionQueryParams); // prepare HTTP request body RequestBody reqBody; String contentType = headerParams.get("Content-Type"); String contentTypePure = contentType; if (contentTypePure != null && contentTypePure.contains(";")) { contentTypePure = contentType.substring(0, contentType.indexOf(";")); } if (!HttpMethod.permitsRequestBody(method)) { reqBody = null; } else if ("application/x-www-form-urlencoded".equals(contentTypePure)) { reqBody = buildRequestBodyFormEncoding(formParams); } else if ("multipart/form-data".equals(contentTypePure)) { reqBody = buildRequestBodyMultipart(formParams); } else if (body == null) { if ("DELETE".equals(method)) { // allow calling DELETE without sending a request body reqBody = null; } else { // use an empty request body (for POST, PUT and PATCH) reqBody = RequestBody.create("", contentType == null ? null : MediaType.parse(contentType)); } } else { reqBody = serialize(body, contentType); } // update parameters with authentication settings updateParamsForAuth(authNames, allQueryParams, headerParams, cookieParams, requestBodyToString(reqBody), method, URI.create(url)); final Request.Builder reqBuilder = new Request.Builder().url(url); processHeaderParams(headerParams, reqBuilder); processCookieParams(cookieParams, reqBuilder); // Associate callback with request (if not null) so interceptor can // access it when creating ProgressResponseBody reqBuilder.tag(callback); Request request = null; if (callback != null && reqBody != null) { ProgressRequestBody progressRequestBody = new ProgressRequestBody(reqBody, callback); request = reqBuilder.method(method, progressRequestBody).build(); } else { request = reqBuilder.method(method, reqBody).build(); } return request; } /** * Build full URL by concatenating base path, the given sub path and query parameters. * * @param baseUrl The base URL * @param path The sub path * @param queryParams The query parameters * @param collectionQueryParams The collection query parameters * @return The full URL */ public String buildUrl(String baseUrl, String path, List queryParams, List collectionQueryParams) { final StringBuilder url = new StringBuilder(); if (baseUrl != null) { url.append(baseUrl).append(path); } else { String baseURL; if (serverIndex != null) { if (serverIndex < 0 || serverIndex >= servers.size()) { throw new ArrayIndexOutOfBoundsException(String.format( "Invalid index %d when selecting the host settings. Must be less than %d", serverIndex, servers.size() )); } baseURL = servers.get(serverIndex).URL(serverVariables); } else { baseURL = basePath; } url.append(baseURL).append(path); } if (queryParams != null && !queryParams.isEmpty()) { // support (constant) query string in `path`, e.g. "/posts?draft=1" String prefix = path.contains("?") ? "&" : "?"; for (Pair param : queryParams) { if (param.getValue() != null) { if (prefix != null) { url.append(prefix); prefix = null; } else { url.append("&"); } String value = parameterToString(param.getValue()); url.append(escapeString(param.getName())).append("=").append(escapeString(value)); } } } if (collectionQueryParams != null && !collectionQueryParams.isEmpty()) { String prefix = url.toString().contains("?") ? "&" : "?"; for (Pair param : collectionQueryParams) { if (param.getValue() != null) { if (prefix != null) { url.append(prefix); prefix = null; } else { url.append("&"); } String value = parameterToString(param.getValue()); // collection query parameter value already escaped as part of parameterToPairs url.append(escapeString(param.getName())).append("=").append(value); } } } return url.toString(); } /** * Set header parameters to the request builder, including default headers. * * @param headerParams Header parameters in the form of Map * @param reqBuilder Request.Builder */ public void processHeaderParams(Map headerParams, Request.Builder reqBuilder) { for (Entry param : headerParams.entrySet()) { reqBuilder.header(param.getKey(), parameterToString(param.getValue())); } for (Entry header : defaultHeaderMap.entrySet()) { if (!headerParams.containsKey(header.getKey())) { reqBuilder.header(header.getKey(), parameterToString(header.getValue())); } } } /** * Set cookie parameters to the request builder, including default cookies. * * @param cookieParams Cookie parameters in the form of Map * @param reqBuilder Request.Builder */ public void processCookieParams(Map cookieParams, Request.Builder reqBuilder) { for (Entry param : cookieParams.entrySet()) { reqBuilder.addHeader("Cookie", String.format("%s=%s", param.getKey(), param.getValue())); } for (Entry param : defaultCookieMap.entrySet()) { if (!cookieParams.containsKey(param.getKey())) { reqBuilder.addHeader("Cookie", String.format("%s=%s", param.getKey(), param.getValue())); } } } /** * Update query and header parameters based on authentication settings. * * @param authNames The authentications to apply * @param queryParams List of query parameters * @param headerParams Map of header parameters * @param cookieParams Map of cookie parameters * @param payload HTTP request body * @param method HTTP method * @param uri URI * @throws com.finbourne.workflow.ApiException If fails to update the parameters */ public void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams, Map cookieParams, String payload, String method, URI uri) throws ApiException { for (String authName : authNames) { Authentication auth = authentications.get(authName); if (auth == null) { throw new RuntimeException("Authentication undefined: " + authName); } auth.applyToParams(queryParams, headerParams, cookieParams, payload, method, uri); } } /** * Build a form-encoding request body with the given form parameters. * * @param formParams Form parameters in the form of Map * @return RequestBody */ public RequestBody buildRequestBodyFormEncoding(Map formParams) { okhttp3.FormBody.Builder formBuilder = new okhttp3.FormBody.Builder(); for (Entry param : formParams.entrySet()) { formBuilder.add(param.getKey(), parameterToString(param.getValue())); } return formBuilder.build(); } /** * Build a multipart (file uploading) request body with the given form parameters, * which could contain text fields and file fields. * * @param formParams Form parameters in the form of Map * @return RequestBody */ public RequestBody buildRequestBodyMultipart(Map formParams) { MultipartBody.Builder mpBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM); for (Entry param : formParams.entrySet()) { if (param.getValue() instanceof File) { File file = (File) param.getValue(); addPartToMultiPartBuilder(mpBuilder, param.getKey(), file); } else if (param.getValue() instanceof List) { List list = (List) param.getValue(); for (Object item: list) { if (item instanceof File) { addPartToMultiPartBuilder(mpBuilder, param.getKey(), (File) item); } else { addPartToMultiPartBuilder(mpBuilder, param.getKey(), param.getValue()); } } } else { addPartToMultiPartBuilder(mpBuilder, param.getKey(), param.getValue()); } } return mpBuilder.build(); } /** * Guess Content-Type header from the given file (defaults to "application/octet-stream"). * * @param file The given file * @return The guessed Content-Type */ public String guessContentTypeFromFile(File file) { String contentType = URLConnection.guessContentTypeFromName(file.getName()); if (contentType == null) { return "application/octet-stream"; } else { return contentType; } } /** * Add a Content-Disposition Header for the given key and file to the MultipartBody Builder. * * @param mpBuilder MultipartBody.Builder * @param key The key of the Header element * @param file The file to add to the Header */ private void addPartToMultiPartBuilder(MultipartBody.Builder mpBuilder, String key, File file) { Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + key + "\"; filename=\"" + file.getName() + "\""); MediaType mediaType = MediaType.parse(guessContentTypeFromFile(file)); mpBuilder.addPart(partHeaders, RequestBody.create(file, mediaType)); } /** * Add a Content-Disposition Header for the given key and complex object to the MultipartBody Builder. * * @param mpBuilder MultipartBody.Builder * @param key The key of the Header element * @param obj The complex object to add to the Header */ private void addPartToMultiPartBuilder(MultipartBody.Builder mpBuilder, String key, Object obj) { RequestBody requestBody; if (obj instanceof String) { requestBody = RequestBody.create((String) obj, MediaType.parse("text/plain")); } else { String content; if (obj != null) { content = JSON.serialize(obj); } else { content = null; } requestBody = RequestBody.create(content, MediaType.parse("application/json")); } Headers partHeaders = Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""); mpBuilder.addPart(partHeaders, requestBody); } /** * Get network interceptor to add it to the httpClient to track download progress for * async requests. */ private Interceptor getProgressInterceptor() { return new Interceptor() { @Override public Response intercept(Interceptor.Chain chain) throws IOException { final Request request = chain.request(); final Response originalResponse = chain.proceed(request); if (request.tag() instanceof ApiCallback) { final ApiCallback callback = (ApiCallback) request.tag(); return originalResponse.newBuilder() .body(new ProgressResponseBody(originalResponse.body(), callback)) .build(); } return originalResponse; } }; } /** * Apply SSL related settings to httpClient according to the current values of * verifyingSsl and sslCaCert. */ private void applySslSettings() { try { TrustManager[] trustManagers; HostnameVerifier hostnameVerifier; if (!verifyingSsl) { trustManagers = new TrustManager[]{ new X509TrustManager() { @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[]{}; } } }; hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }; } else { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); if (sslCaCert == null) { trustManagerFactory.init((KeyStore) null); } else { char[] password = null; // Any password will work. CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); Collection certificates = certificateFactory.generateCertificates(sslCaCert); if (certificates.isEmpty()) { throw new IllegalArgumentException("expected non-empty set of trusted certificates"); } KeyStore caKeyStore = newEmptyKeyStore(password); int index = 0; for (Certificate certificate : certificates) { String certificateAlias = "ca" + (index++); caKeyStore.setCertificateEntry(certificateAlias, certificate); } trustManagerFactory.init(caKeyStore); } trustManagers = trustManagerFactory.getTrustManagers(); hostnameVerifier = OkHostnameVerifier.INSTANCE; } SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, trustManagers, new SecureRandom()); httpClient = httpClient.newBuilder() .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0]) .hostnameVerifier(hostnameVerifier) .build(); } catch (GeneralSecurityException e) { throw new RuntimeException(e); } } private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { try { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, password); return keyStore; } catch (IOException e) { throw new AssertionError(e); } } /** * Convert the HTTP request body to a string. * * @param requestBody The HTTP request object * @return The string representation of the HTTP request body * @throws com.finbourne.workflow.ApiException If fail to serialize the request body object into a string */ private String requestBodyToString(RequestBody requestBody) throws ApiException { if (requestBody != null) { try { final Buffer buffer = new Buffer(); requestBody.writeTo(buffer); return buffer.readUtf8(); } catch (final IOException e) { throw new ApiException(e); } } // empty http request body return ""; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy