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

com.okta.sdk.resource.client.ApiClient Maven / Gradle / Ivy

Go to download

The Okta Java SDK API .jar provides a Java API that your code can use to make calls to the Okta API. This .jar is the only compile-time dependency within the Okta SDK project that your code should depend on. Implementations of this API (implementation .jars) should be runtime dependencies only.

There is a newer version: 21.0.0
Show newest version
package com.okta.sdk.resource.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.time.OffsetDateTime;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import org.openapitools.jackson.nullable.JsonNullableModule;

import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.Cookie;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.FileEntity;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
import org.apache.hc.core5.http.message.BasicNameValuePair;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Objects;
import java.util.Map.Entry;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.net.URLEncoder;

import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.nio.file.Paths;
import java.lang.reflect.Type;
import java.net.URI;

import com.okta.sdk.cache.Caches;
import com.okta.sdk.cache.Cache;
import com.okta.sdk.cache.CacheManager;

import com.okta.sdk.resource.common.PagedList;

import com.okta.sdk.resource.model.HttpMethod;

import java.text.DateFormat;

import com.okta.sdk.resource.client.auth.Authentication;
import com.okta.sdk.resource.client.auth.ApiKeyAuth;
import com.okta.sdk.resource.client.auth.OAuth;

@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2024-11-15T08:48:47.130589-06:00[America/Chicago]", comments = "Generator version: 7.8.0")
public class ApiClient extends JavaTimeFormatter {

    private static final Logger log = LoggerFactory.getLogger(ApiClient.class);

    private Map defaultHeaderMap = new HashMap();
    private Map defaultCookieMap = new HashMap();
    private String basePath = "https://subdomain.okta.com";
    protected List servers = new ArrayList(
            Arrays.asList(new ServerConfiguration("https://{yourOktaDomain}", "No description provided",
                    new HashMap() {
                        {
                            put("yourOktaDomain", new ServerVariable(
                                    "The domain of your organization. This can be a provided subdomain of an official okta domain (okta.com, oktapreview.com, etc) or one of your configured custom domains.",
                                    "subdomain.okta.com", new HashSet()));
                        }
                    })));
    protected Integer serverIndex = 0;
    protected Map serverVariables = null;
    private boolean debugging = false;
    private int connectionTimeout = 0;

    private CloseableHttpClient httpClient;
    private ObjectMapper objectMapper;
    protected String tempFolderPath = null;

    private Map authentications;

    private Cache cache;

    private int statusCode;
    private Map> responseHeaders;

    private DateFormat dateFormat;

    // Methods that can have a request body
    private static List bodyMethods = Arrays.asList("POST", "PUT", "DELETE", "PATCH");

    public ApiClient(CloseableHttpClient httpClient, CacheManager cacheManager) {
        if (httpClient == null)
            throw new IllegalArgumentException("httpClient cannot be null");
        if (cacheManager == null)
            throw new IllegalArgumentException("cacheManager cannot be null");

        objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false);
        objectMapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
        objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.registerModule(new JsonNullableModule());
        objectMapper.setDateFormat(ApiClient.buildDefaultDateFormat());

        dateFormat = ApiClient.buildDefaultDateFormat();

        // Setup authentications (key: authentication name, value: authentication).
        authentications = new HashMap();
        authentications.put("apiToken", new ApiKeyAuth("header", "Authorization"));
        authentications.put("oauth2", new OAuth());
        // Prevent the authentications from being modified.
        authentications = Collections.unmodifiableMap(authentications);

        this.httpClient = httpClient;

        this.cache = cacheManager.getCache("default");
    }

    public ApiClient() {
        this(HttpClients.createDefault(), Caches.newDisabledCacheManager());
    }

    public static DateFormat buildDefaultDateFormat() {
        return new RFC3339DateFormat();
    }

    /**
     * Returns the current object mapper used for JSON serialization/deserialization.
     * 

* Note: If you make changes to the object mapper, remember to set it back via setObjectMapper in order * to trigger HTTP client rebuilding. *

* * @return Object mapper */ public ObjectMapper getObjectMapper() { return objectMapper; } /** * Sets the object mapper. * * @param objectMapper * object mapper * * @return API client */ public ApiClient setObjectMapper(ObjectMapper objectMapper) { this.objectMapper = objectMapper; return this; } public CloseableHttpClient getHttpClient() { return httpClient; } /** * Sets the HTTP client. * * @param httpClient * HTTP client * * @return API client */ public ApiClient setHttpClient(CloseableHttpClient httpClient) { this.httpClient = httpClient; return this; } public String getBasePath() { return basePath; } /** * Sets the base path. * * @param basePath * base path * * @return API client */ public ApiClient setBasePath(String basePath) { this.basePath = basePath; this.serverIndex = null; return this; } public List getServers() { return servers; } /** * Sets the server. * * @param servers * a list of server configuration * * @return API client */ public ApiClient setServers(List servers) { this.servers = servers; return this; } public Integer getServerIndex() { return serverIndex; } /** * Sets the server index. * * @param serverIndex * server index * * @return API client */ public ApiClient setServerIndex(Integer serverIndex) { this.serverIndex = serverIndex; return this; } public Map getServerVariables() { return serverVariables; } /** * Sets the server variables. * * @param serverVariables * server variables * * @return API client */ public ApiClient setServerVariables(Map serverVariables) { this.serverVariables = serverVariables; return this; } /** * Gets the status code of the previous request * * @return Status code */ public int getStatusCode() { return statusCode; } /** * Gets the response headers of the previous request * * @return Response headers */ public Map> getResponseHeaders() { return responseHeaders; } /** * Get authentications (key: authentication name, value: authentication). * * @return Map of authentication */ 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); } /** * Replaces authentication for the given name. * * @param authName * The authentication name * @param authentication * The new implementation (must be of the same type of the existing implementation) */ public void replaceAuthentication(String authName, Authentication authentication) { Authentication previous = authentications.get(authName); if (previous == null) { throw new RuntimeException(authName + " authentication not configured!"); } if (!previous.getClass().isAssignableFrom(authentication.getClass())) { throw new RuntimeException( authentication.getClass().getSimpleName() + " cannot replace authentication " + authName); } authentications = new HashMap<>(authentications); authentications.put(authName, authentication); authentications = Collections.unmodifiableMap(authentications); } /** * 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. * * @return Temp folder path */ public String getTempFolderPath() { return tempFolderPath; } /** * Helper method to set API key value for the first API key authentication. * * @param apiKey * the API key * * @return API client */ public ApiClient setApiKey(String apiKey) { for (Authentication auth : authentications.values()) { if (auth instanceof ApiKeyAuth) { ((ApiKeyAuth) auth).setApiKey(apiKey); return this; } } 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 * * @return API client */ public ApiClient setApiKeyPrefix(String apiKeyPrefix) { for (Authentication auth : authentications.values()) { if (auth instanceof ApiKeyAuth) { ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix); return this; } } throw new RuntimeException("No API key authentication configured!"); } /** * Helper method to set access token for the first OAuth2 authentication. * * @param accessToken * Access token * * @return API client */ public ApiClient setAccessToken(String accessToken) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).setAccessToken(accessToken); return this; } } throw new RuntimeException("No OAuth2 authentication configured!"); } /** * Set the User-Agent header's value (by adding to the default header map). * * @param userAgent * User agent * * @return API client */ public ApiClient setUserAgent(String userAgent) { addDefaultHeader("User-Agent", userAgent); return this; } /** * Set temp folder path * * @param tempFolderPath * Temp folder path * * @return API client */ public ApiClient setTempFolderPath(String tempFolderPath) { this.tempFolderPath = tempFolderPath; return this; } /** * Add a default header. * * @param key * The header's key * @param value * The header's value * * @return API client */ 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 API client */ 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 on */ public boolean isDebugging() { return debugging; } /** * Enable/disable debugging for this API client. * * @param debugging * To enable (true) or disable (false) debugging * * @return API client */ public ApiClient setDebugging(boolean debugging) { // TODO: implement debugging mode this.debugging = debugging; return this; } /** * Connect timeout (in milliseconds). * * @return Connection timeout */ public int getConnectTimeout() { return connectionTimeout; } /** * Set the connect timeout (in milliseconds). A value of 0 means no timeout, otherwise values must be between 1 and * {@link Integer#MAX_VALUE}. * * @param connectionTimeout * Connection timeout in milliseconds * * @return API client */ public ApiClient setConnectTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; return this; } /** * Get the date format used to parse/format date parameters. * * @return Date format */ public DateFormat getDateFormat() { return dateFormat; } /** * Set the date format used to parse/format date parameters. * * @param dateFormat * Date format * * @return API client */ public ApiClient setDateFormat(DateFormat dateFormat) { this.dateFormat = dateFormat; // Also set the date format for model (de)serialization with Date properties. this.objectMapper.setDateFormat((DateFormat) dateFormat.clone()); return this; } /** * Parse the given string into Date object. * * @param str * String * * @return Date */ public Date parseDate(String str) { try { return dateFormat.parse(str); } catch (java.text.ParseException e) { throw new RuntimeException(e); } } /** * Format the given Date object into string. * * @param date * Date * * @return Date in string format */ public String formatDate(Date date) { return dateFormat.format(date); } /** * Format the given parameter object into string. * * @param param * Object * * @return Object in string format */ public String parameterToString(Object param) { if (param == null) { return ""; } else if (param instanceof Date) { return formatDate((Date) param); } else if (param instanceof OffsetDateTime) { return formatOffsetDateTime((OffsetDateTime) param); } else if (param instanceof Collection) { StringBuilder b = new StringBuilder(); for (Object o : (Collection) param) { if (b.length() > 0) { b.append(','); } b.append(String.valueOf(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, escapeString(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) { 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; } /** * Check if the given MIME is a JSON MIME. JSON MIME examples: application/json application/json; charset=UTF8 * APPLICATION/JSON application/vnd.company+json * * @param mime * MIME * * @return True if MIME type is boolean */ 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, or matches "any", JSON will be used. */ public String selectHeaderContentType(String[] contentTypes) { if (contentTypes.length == 0 || 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 * * @return Escaped string */ public String escapeString(String str) { try { return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20"); } catch (UnsupportedEncodingException e) { return str; } } /** * Transforms response headers into map. * * @param headers * HTTP headers * * @return a map of string array */ protected Map> transformResponseHeaders(Header[] headers) { Map> headersMap = new HashMap<>(); for (Header header : headers) { List valuesList = headersMap.get(header.getName()); if (valuesList != null) { valuesList.add(header.getValue()); } else { valuesList = new ArrayList<>(); valuesList.add(header.getValue()); headersMap.put(header.getName(), valuesList); } } return headersMap; } /** * Parse content type object from header value */ private ContentType getContentType(String headerValue) throws ApiException { try { return ContentType.parse(headerValue); } catch (UnsupportedCharsetException e) { throw new ApiException("Could not parse content type " + headerValue); } } /** * Get content type of a response or null if one was not provided */ private String getResponseMimeType(HttpResponse response) throws ApiException { Header contentTypeHeader = response.getFirstHeader("Content-Type"); if (contentTypeHeader != null) { return getContentType(contentTypeHeader.getValue()).getMimeType(); } return null; } /** * Serialize the given Java object into string according the given Content-Type (only JSON is supported for now). * * @param obj * Object * @param contentType * Content type * @param formParams * Form parameters * * @return Object * * @throws ApiException * API exception */ public HttpEntity serialize(Object obj, Map formParams, ContentType contentType) throws ApiException { String mimeType = contentType.getMimeType(); if (isJsonMime(mimeType)) { try { return new StringEntity(objectMapper.writeValueAsString(obj), ContentType.APPLICATION_JSON); } catch (JsonProcessingException e) { throw new ApiException(e); } } else if (mimeType.equals(ContentType.MULTIPART_FORM_DATA.getMimeType())) { MultipartEntityBuilder multiPartBuilder = MultipartEntityBuilder.create(); for (Entry paramEntry : formParams.entrySet()) { Object value = paramEntry.getValue(); if (value instanceof File) { multiPartBuilder.addBinaryBody(paramEntry.getKey(), (File) value); } else if (value instanceof byte[]) { multiPartBuilder.addBinaryBody(paramEntry.getKey(), (byte[]) value); } else { Charset charset = contentType.getCharset(); if (charset != null) { ContentType customContentType = ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), charset); multiPartBuilder.addTextBody(paramEntry.getKey(), parameterToString(paramEntry.getValue()), customContentType); } else { multiPartBuilder.addTextBody(paramEntry.getKey(), parameterToString(paramEntry.getValue())); } } } return multiPartBuilder.build(); } else if (mimeType.equals(ContentType.APPLICATION_FORM_URLENCODED.getMimeType())) { List formValues = new ArrayList<>(); for (Entry paramEntry : formParams.entrySet()) { formValues.add(new BasicNameValuePair(paramEntry.getKey(), parameterToString(paramEntry.getValue()))); } return new UrlEncodedFormEntity(formValues, contentType.getCharset()); } else { // Handle files with unknown content type if (obj instanceof File) { return new FileEntity((File) obj, contentType); } else if (obj instanceof byte[]) { return new ByteArrayEntity((byte[]) obj, contentType); } throw new ApiException("Serialization for content type '" + contentType + "' not supported"); } } /** * Deserialize response body to Java object according to the Content-Type. * * @param * Type * @param response * Response * @param valueType * Return type * * @return Deserialized object * * @throws ApiException * API exception * @throws IOException * IO exception */ @SuppressWarnings("unchecked") public T deserialize(CloseableHttpResponse response, TypeReference valueType) throws ApiException, IOException, ParseException { if (valueType == null) { return null; } HttpEntity entity = response.getEntity(); Type valueRawType = valueType.getType(); if (valueRawType.equals(byte[].class)) { return (T) EntityUtils.toByteArray(entity); } else if (valueRawType.equals(File.class)) { return (T) downloadFileFromResponse(response); } String mimeType = getResponseMimeType(response); if (mimeType == null || isJsonMime(mimeType)) { // Assume json if no mime type // convert input stream to string java.util.Scanner s = new java.util.Scanner(entity.getContent()).useDelimiter("\\A"); String content = (String) (s.hasNext() ? s.next() : ""); if ("".equals(content)) { // returns null for empty body return null; } // some responses of list type contain a root element that need to be stripped before passing to // ObjectMapper if (valueRawType.getTypeName().contains("java.util.List")) { if (content.startsWith("{\"")) { // remove leading {"blahblah": content = content.substring(content.indexOf(":") + 1); // remove trailing } content = content.substring(0, content.length() - 1); } } T value = objectMapper.readValue(content, valueType); return value instanceof List ? PagedList.constructPagedList(response, value) : value; } else if ("text/plain".equalsIgnoreCase(mimeType)) { // convert input stream to string java.util.Scanner s = new java.util.Scanner(entity.getContent()).useDelimiter("\\A"); return (T) (s.hasNext() ? s.next() : ""); } else { throw new ApiException( "Deserialization for content type '" + mimeType + "' not supported for type '" + valueType + "'", response.getCode(), responseHeaders, EntityUtils.toString(entity)); } } private File downloadFileFromResponse(CloseableHttpResponse response) throws IOException { Header contentDispositionHeader = response.getFirstHeader("Content-Disposition"); String contentDisposition = contentDispositionHeader == null ? null : contentDispositionHeader.getValue(); File file = prepareDownloadFile(contentDisposition); Files.copy(response.getEntity().getContent(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); return file; } protected File prepareDownloadFile(String contentDisposition) throws IOException { String filename = null; 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 = matcher.group(1); } String prefix; 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(); } /** * Build full URL by concatenating base path, the given sub path and query parameters. * * @param path * The sub path * @param queryParams * The query parameters * @param collectionQueryParams * The collection query parameters * @param urlQueryDeepObject * URL query string of the deep object parameters * * @return The full URL */ private String buildUrl(String path, List queryParams, List collectionQueryParams, String urlQueryDeepObject) { 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; } final StringBuilder url = new StringBuilder(); 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()); // query parameter value already escaped as part of parameterToPair url.append(escapeString(param.getName())).append("=").append(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); } } } if (urlQueryDeepObject != null && urlQueryDeepObject.length() > 0) { url.append(url.toString().contains("?") ? "&" : "?"); url.append(urlQueryDeepObject); } return url.toString(); } protected boolean isSuccessfulStatus(int statusCode) { return statusCode >= 200 && statusCode < 300; } protected boolean isBodyAllowed(String method) { return bodyMethods.contains(method); } protected Cookie buildCookie(String key, String value, URI uri) { BasicClientCookie cookie = new BasicClientCookie(key, value); cookie.setDomain(uri.getHost()); cookie.setPath("/"); return cookie; } protected T processResponse(CloseableHttpResponse response, TypeReference returnType) throws ApiException, IOException, ParseException { statusCode = response.getCode(); if (statusCode == HttpStatus.SC_NO_CONTENT) { return null; } responseHeaders = transformResponseHeaders(response.getHeaders()); if (isSuccessfulStatus(statusCode)) { return this.deserialize(response, returnType); } else { String message = EntityUtils.toString(response.getEntity()); throw new ApiException(message, statusCode, responseHeaders, message); } } /** * Invoke API by sending HTTP request with the given options. * * @param * Type * @param path * The sub-path of the HTTP URL * @param method * The request method, one of "GET", "POST", "PUT", and "DELETE" * @param queryParams * The query parameters * @param collectionQueryParams * The collection query parameters * @param urlQueryDeepObject * A URL query string for deep object parameters * @param body * The request body object - if it is not binary, otherwise null * @param headerParams * The header parameters * @param cookieParams * The cookie parameters * @param formParams * The form parameters * @param accept * The request's Accept header * @param contentType * The request's Content-Type header * @param authNames * The authentications to apply * @param returnType * Return type * * @return The response body in type of string * * @throws ApiException * API exception */ public T invokeAPI(String path, String method, List queryParams, List collectionQueryParams, String urlQueryDeepObject, Object body, Map headerParams, Map cookieParams, Map formParams, String accept, String contentType, String[] authNames, TypeReference returnType) throws ApiException { if (body != null && !formParams.isEmpty()) { throw new ApiException("Cannot have body and form params"); } updateParamsForAuth(authNames, queryParams, headerParams, cookieParams); final String url = buildUrl(path, queryParams, collectionQueryParams, urlQueryDeepObject); ClassicRequestBuilder builder = ClassicRequestBuilder.create(method); builder.setUri(url); if (accept != null) { builder.addHeader("Accept", accept); } for (Entry keyValue : headerParams.entrySet()) { builder.addHeader(keyValue.getKey(), keyValue.getValue()); } for (Map.Entry keyValue : defaultHeaderMap.entrySet()) { if (!headerParams.containsKey(keyValue.getKey())) { builder.addHeader(keyValue.getKey(), keyValue.getValue()); } } BasicCookieStore store = new BasicCookieStore(); for (Entry keyValue : cookieParams.entrySet()) { store.addCookie(buildCookie(keyValue.getKey(), keyValue.getValue(), builder.getUri())); } for (Entry keyValue : defaultCookieMap.entrySet()) { if (!cookieParams.containsKey(keyValue.getKey())) { store.addCookie(buildCookie(keyValue.getKey(), keyValue.getValue(), builder.getUri())); } } HttpClientContext context = HttpClientContext.create(); context.setCookieStore(store); ContentType contentTypeObj = getContentType(contentType); if (body != null || !formParams.isEmpty()) { if (isBodyAllowed(method)) { // Add entity if we have content and a valid method builder.setEntity(serialize(body, formParams, contentTypeObj)); } else { throw new ApiException("method " + method + " does not support a request body"); } } else { // for empty body builder.setEntity(new StringEntity("", contentTypeObj)); } String cacheKey = url; if (Objects.nonNull(path)) { cacheKey = cacheKey.split("\\?")[0]; } if (method == HttpMethod.DELETE.name()) { cache.remove(cacheKey); } String[] uriSegments = path.split("/"); if (uriSegments != null && uriSegments.length >= 6) { String key = getBasePath() + "/" + uriSegments[1] + "/" + uriSegments[2] + "/" + uriSegments[3] + "/" + uriSegments[4]; if (cache.get(key) != null) { cache.remove(key); } } if (method == HttpMethod.GET.name() && !returnType.getType().getTypeName().contains("List") && !(url.contains("expand")) && !(url.contains(".well-known/okta-organization"))) { T cacheData = (T) cache.get(cacheKey); if (Objects.isNull(cacheData)) { try (CloseableHttpResponse response = httpClient.execute(builder.build(), context)) { T t = processResponse(response, returnType); if (method.equals(HttpMethod.GET.name()) && Objects.nonNull(t)) { Map map = getObjectMapper().convertValue(t, LinkedHashMap.class); String href = null; if (Objects.nonNull(map)) { Map links = (Map) map.get("_links"); if (Objects.nonNull(links)) { LinkedHashMap self = links.get("self"); if (Objects.nonNull(self)) { href = (String) self.get("href"); } } } if (Objects.nonNull(href)) { cache.put(href, t); } else { cache.put(cacheKey, t); } } return t; } catch (IOException | ParseException e) { throw new ApiException(e); } } else { // return data from cache return (T) cache.get(cacheKey); } } else { try (CloseableHttpResponse response = httpClient.execute(builder.build(), context)) { T t = processResponse(response, returnType); if (cache.get(cacheKey) != null && !method.equals(HttpMethod.DELETE.name())) { cache.put(cacheKey, t); } return t; } catch (IOException | ParseException e) { throw new ApiException(e); } } } /** * Update query and header parameters based on authentication settings. * * @param authNames * The authentications to apply * @param queryParams * Query parameters * @param headerParams * Header parameters * @param cookieParams * Cookie parameters */ private void updateParamsForAuth(String[] authNames, List queryParams, Map headerParams, Map cookieParams) { for (String authName : authNames) { Authentication auth = authentications.get(authName); if (auth == null) throw new RuntimeException("Authentication undefined: " + authName); auth.applyToParams(queryParams, headerParams, cookieParams); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy