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

custom_templates.ApiClient.mustache 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: 20.0.0
Show newest version
{{!
    Copyright (c) 2022-Present, Okta, Inc.

    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 {{invokerPackage}};

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

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
{{#joda}}
    import com.fasterxml.jackson.datatype.joda.JodaModule;
{{/joda}}
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;
{{#openApiNullable}}
    import org.openapitools.jackson.nullable.JsonNullableModule;
{{/openApiNullable}}

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 {{invokerPackage}}.auth.Authentication;
{{#hasHttpBasicMethods}}
    import {{invokerPackage}}.auth.HttpBasicAuth;
{{/hasHttpBasicMethods}}
{{#hasHttpBearerMethods}}
    import {{invokerPackage}}.auth.HttpBearerAuth;
{{/hasHttpBearerMethods}}
{{#hasApiKeyMethods}}
    import {{invokerPackage}}.auth.ApiKeyAuth;
{{/hasApiKeyMethods}}
{{#hasOAuthMethods}}
    import {{invokerPackage}}.auth.OAuth;
{{/hasOAuthMethods}}

{{>generatedAnnotation}}
public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} {

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

private Map defaultHeaderMap = new HashMap();
private Map defaultCookieMap = new HashMap();
private String basePath = "{{{basePath}}}";
protected List servers = new ArrayList({{#servers}}{{#-first}}Arrays.asList(
{{/-first}}    new ServerConfiguration(
    "{{{url}}}",
    "{{{description}}}{{^description}}No description provided{{/description}}",
    new HashMap(){{#variables}}{{#-first}} {{
    {{/-first}}        put("{{{name}}}", new ServerVariable(
        "{{{description}}}{{^description}}No description provided{{/description}}",
        "{{{defaultValue}}}",
        new HashSet(
        {{#enumValues}}
            {{#-first}}
                Arrays.asList(
            {{/-first}}
            "{{{.}}}"{{^-last}},{{/-last}}
            {{#-last}}
                )
            {{/-last}}
        {{/enumValues}}
        )
        ));
        {{#-last}}
            }}{{/-last}}{{/variables}}
    ){{^-last}},{{/-last}}
    {{#-last}}
        ){{/-last}}{{/servers}});
    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);
            {{#joda}}
                objectMapper.registerModule(new JodaModule());
            {{/joda}}
            objectMapper.registerModule(new JavaTimeModule());
            {{#openApiNullable}}
                objectMapper.registerModule(new JsonNullableModule());
            {{/openApiNullable}}
            objectMapper.setDateFormat(ApiClient.buildDefaultDateFormat());

            dateFormat = ApiClient.buildDefaultDateFormat();

            // Setup authentications (key: authentication name, value: authentication).
            authentications = new HashMap();{{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
                authentications.put("{{name}}", new HttpBasicAuth());{{/isBasicBasic}}{{#isBasicBearer}}
                authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));{{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}
                authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));{{/isApiKey}}{{#isOAuth}}
                authentications.put("{{name}}", new OAuth());{{/isOAuth}}{{/authMethods}}
            // 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; } {{#hasHttpBearerMethods}} /** * Helper method to set access token for the first Bearer authentication. * @param bearerToken Bearer token * @return API client */ public ApiClient setBearerToken(String bearerToken) { for (Authentication auth : authentications.values()) { if (auth instanceof HttpBearerAuth) { ((HttpBearerAuth) auth).setBearerToken(bearerToken); return this; } } throw new RuntimeException("No Bearer authentication configured!"); } {{/hasHttpBearerMethods}} {{#hasHttpBasicMethods}} /** * Helper method to set username for the first HTTP basic authentication. * @param username Username * @return API client */ public ApiClient setUsername(String username) { for (Authentication auth : authentications.values()) { if (auth instanceof HttpBasicAuth) { ((HttpBasicAuth) auth).setUsername(username); return this; } } throw new RuntimeException("No HTTP basic authentication configured!"); } /** * Helper method to set password for the first HTTP basic authentication. * @param password Password * @return API client */ public ApiClient setPassword(String password) { for (Authentication auth : authentications.values()) { if (auth instanceof HttpBasicAuth) { ((HttpBasicAuth) auth).setPassword(password); return this; } } throw new RuntimeException("No HTTP basic authentication configured!"); } {{/hasHttpBasicMethods}} {{#hasApiKeyMethods}} /** * 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!"); } {{/hasApiKeyMethods}} {{#hasOAuthMethods}} /** * 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!"); } {{/hasOAuthMethods}} /** * 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); } {{#jsr310}}else if (param instanceof OffsetDateTime) { return formatOffsetDateTime((OffsetDateTime) param); } {{/jsr310}}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; } 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