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

Java.libraries.jersey2.ApiClient.mustache Maven / Gradle / Ivy

There is a newer version: 7.9.0
Show newest version
{{>licenseInfo}}

package {{invokerPackage}};

import {{javaxPackage}}.ws.rs.client.Client;
import {{javaxPackage}}.ws.rs.client.ClientBuilder;
import {{javaxPackage}}.ws.rs.client.Entity;
import {{javaxPackage}}.ws.rs.client.Invocation;
import {{javaxPackage}}.ws.rs.client.WebTarget;
import {{javaxPackage}}.ws.rs.core.Form;
import {{javaxPackage}}.ws.rs.core.GenericType;
import {{javaxPackage}}.ws.rs.core.MediaType;
import {{javaxPackage}}.ws.rs.core.Response;
import {{javaxPackage}}.ws.rs.core.Response.Status;

{{#hasOAuthMethods}}
import com.github.scribejava.core.model.OAuth2AccessToken;
{{/hasOAuthMethods}}
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.MultiPartFeature;

import java.io.IOException;
import java.io.InputStream;

import java.net.URI;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import org.glassfish.jersey.logging.LoggingFeature;
import java.util.AbstractMap.SimpleEntry;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.stream.Stream;
{{#jsr310}}
import java.time.OffsetDateTime;
{{/jsr310}}

import java.net.URLEncoder;

import java.io.File;
import java.io.UnsupportedEncodingException;

import java.text.DateFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import {{invokerPackage}}.auth.Authentication;
import {{invokerPackage}}.auth.HttpBasicAuth;
import {{invokerPackage}}.auth.HttpBearerAuth;
{{#hasHttpSignatureMethods}}
import {{invokerPackage}}.auth.HttpSignatureAuth;
{{/hasHttpSignatureMethods}}
import {{invokerPackage}}.auth.ApiKeyAuth;
{{#hasOAuthMethods}}
import {{invokerPackage}}.auth.OAuth;
{{/hasOAuthMethods}}

/**
 * 

ApiClient class.

*/ {{>generatedAnnotation}} public class ApiClient{{#jsr310}} extends JavaTimeFormatter{{/jsr310}} { private static final Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$"); protected Map defaultHeaderMap = new HashMap<>(); protected Map defaultCookieMap = new HashMap<>(); protected String basePath = "{{{basePath}}}"; protected String userAgent; private static final Logger log = Logger.getLogger(ApiClient.class.getName()); protected List servers = new ArrayList<>({{#servers}}{{#-first}}Arrays.asList( {{/-first}} new ServerConfiguration( "{{{url}}}", "{{{description}}}{{^description}}No description provided{{/description}}", {{^variables}} new LinkedHashMap<>() {{/variables}} {{#variables}} {{#-first}} Stream.>of( {{/-first}} new SimpleEntry<>("{{{name}}}", new ServerVariable( "{{{description}}}{{^description}}No description provided{{/description}}", "{{{defaultValue}}}", new LinkedHashSet<>({{#enumValues}}{{#-first}}Arrays.asList({{/-first}} "{{{.}}}"{{^-last}},{{/-last}}{{#-last}} ){{/-last}}{{/enumValues}}) )){{^-last}},{{/-last}} {{#-last}} ).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> a, LinkedHashMap::new)) {{/-last}} {{/variables}} ){{^-last}},{{/-last}} {{#-last}} ){{/-last}}{{/servers}}); protected Integer serverIndex = 0; protected Map serverVariables = null; {{^hasOperationServers}} protected Map> operationServers = new HashMap<>(); {{/hasOperationServers}} {{#hasOperationServers}} protected Map> operationServers; { Map> operationServers = new HashMap<>(); {{#apiInfo}} {{#apis}} {{#operations}} {{#operation}} {{#servers}} {{#-first}} operationServers.put("{{{classname}}}.{{{operationId}}}", new ArrayList<>(Arrays.asList( {{/-first}} new ServerConfiguration( "{{{url}}}", "{{{description}}}{{^description}}No description provided{{/description}}", {{^variables}} new LinkedHashMap<>() {{/variables}} {{#variables}} {{#-first}} Stream.>of( {{/-first}} new SimpleEntry<>("{{{name}}}", new ServerVariable( "{{{description}}}{{^description}}No description provided{{/description}}", "{{{defaultValue}}}", new LinkedHashSet<>({{#enumValues}}{{#-first}}Arrays.asList({{/-first}} "{{{.}}}"{{^-last}},{{/-last}}{{#-last}} ){{/-last}}{{/enumValues}}) )){{^-last}},{{/-last}} {{#-last}} ).collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> a, LinkedHashMap::new)) {{/-last}} {{/variables}} ){{^-last}},{{/-last}} {{#-last}} ))); {{/-last}} {{/servers}} {{/operation}} {{/operations}} {{/apis}} {{/apiInfo}} this.operationServers = operationServers; } {{/hasOperationServers}} protected Map operationServerIndex = new HashMap<>(); protected Map> operationServerVariables = new HashMap<>(); protected boolean debugging = false; protected ClientConfig clientConfig; protected int connectionTimeout = 0; private int readTimeout = 0; protected Client httpClient; protected JSON json; protected String tempFolderPath = null; protected Map authentications; protected Map authenticationLookup; protected DateFormat dateFormat; /** * Constructs a new ApiClient with default parameters. */ public ApiClient() { this(null); } /** * Constructs a new ApiClient with the specified authentication parameters. * * @param authMap A hash map containing authentication parameters. */ public ApiClient(Map authMap) { json = new JSON(); httpClient = buildHttpClient(); this.dateFormat = new RFC3339DateFormat(); // Set default User-Agent. setUserAgent("{{{httpUserAgent}}}{{^httpUserAgent}}OpenAPI-Generator/{{{artifactVersion}}}/java{{/httpUserAgent}}"); // Setup authentications (key: authentication name, value: authentication). authentications = new HashMap<>(); Authentication auth = null; {{#authMethods}} if (authMap != null) { auth = authMap.get("{{name}}"); } {{#isBasic}} {{#isBasicBasic}} if (auth instanceof HttpBasicAuth) { authentications.put("{{name}}", auth); } else { authentications.put("{{name}}", new HttpBasicAuth()); } {{/isBasicBasic}} {{#isBasicBearer}} if (auth instanceof HttpBearerAuth) { authentications.put("{{name}}", auth); } else { authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}")); } {{/isBasicBearer}} {{#isHttpSignature}} if (auth instanceof HttpSignatureAuth) { authentications.put("{{name}}", auth); } {{/isHttpSignature}} {{/isBasic}} {{#isApiKey}} if (auth instanceof ApiKeyAuth) { authentications.put("{{name}}", auth); } else { authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}")); } {{/isApiKey}} {{#isOAuth}} if (auth instanceof OAuth) { authentications.put("{{name}}", auth); } else { authentications.put("{{name}}", new OAuth(basePath, "{{{tokenUrl}}}")); } {{/isOAuth}} {{/authMethods}} // Prevent the authentications from being modified. authentications = Collections.unmodifiableMap(authentications); // Setup authentication lookup (key: authentication alias, value: authentication name) authenticationLookup = new HashMap<>();{{#authMethods}}{{#vendorExtensions.x-auth-id-alias}} authenticationLookup.put("{{name}}", "{{.}}");{{/vendorExtensions.x-auth-id-alias}}{{/authMethods}} } /** * Gets the JSON instance to do JSON serialization and deserialization. * * @return JSON */ public JSON getJSON() { return json; } /** *

Getter for the field httpClient.

* * @return a {@link {{javaxPackage}}.ws.rs.client.Client} object. */ public Client getHttpClient() { return httpClient; } /** *

Setter for the field httpClient.

* * @param httpClient a {@link {{javaxPackage}}.ws.rs.client.Client} object. * @return a {@link ApiClient} object. */ public ApiClient setHttpClient(Client httpClient) { this.httpClient = httpClient; return this; } /** * Returns the base URL to the location where the OpenAPI document is being served. * * @return The base URL to the target host. */ public String getBasePath() { return basePath; } /** * Sets the base URL to the location where the OpenAPI document is being served. * * @param basePath The base URL to the target host. * @return a {@link ApiClient} object. */ public ApiClient setBasePath(String basePath) { this.basePath = basePath; {{#hasOAuthMethods}} setOauthBasePath(basePath); {{/hasOAuthMethods}} return this; } /** *

Getter for the field servers.

* * @return a {@link java.util.List} of servers. */ public List getServers() { return servers; } /** *

Setter for the field servers.

* * @param servers a {@link java.util.List} of servers. * @return a {@link ApiClient} object. */ public ApiClient setServers(List servers) { this.servers = servers; updateBasePath(); return this; } /** *

Getter for the field serverIndex.

* * @return a {@link java.lang.Integer} object. */ public Integer getServerIndex() { return serverIndex; } /** *

Setter for the field serverIndex.

* * @param serverIndex the server index * @return a {@link ApiClient} object. */ public ApiClient setServerIndex(Integer serverIndex) { this.serverIndex = serverIndex; updateBasePath(); return this; } /** *

Getter for the field serverVariables.

* * @return a {@link java.util.Map} of server variables. */ public Map getServerVariables() { return serverVariables; } /** *

Setter for the field serverVariables.

* * @param serverVariables a {@link java.util.Map} of server variables. * @return a {@link ApiClient} object. */ public ApiClient setServerVariables(Map serverVariables) { this.serverVariables = serverVariables; updateBasePath(); return this; } private void updateBasePath() { if (serverIndex != null) { setBasePath(servers.get(serverIndex).URL(serverVariables)); } } {{#hasOAuthMethods}} private void setOauthBasePath(String basePath) { for(Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).setBasePath(basePath); } } } {{/hasOAuthMethods}} /** * Get authentications (key: authentication name, value: authentication). * * @return Map of authentication object */ 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 * @return a {@link ApiClient} object. */ 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 a {@link ApiClient} object. */ 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!"); } /** * Helper method to set API key value for the first API key authentication. * * @param apiKey API key * @return a {@link ApiClient} object. */ 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 configure authentications which respects aliases of API keys. * * @param secrets Hash map from authentication name to its secret. * @return a {@link ApiClient} object. */ public ApiClient configureApiKeys(Map secrets) { for (Map.Entry authEntry : authentications.entrySet()) { Authentication auth = authEntry.getValue(); if (auth instanceof ApiKeyAuth) { String name = authEntry.getKey(); // respect x-auth-id-alias property name = authenticationLookup.getOrDefault(name, name); String secret = secrets.get(name); if (secret != null) { ((ApiKeyAuth) auth).setApiKey(secret); } } } return this; } /** * Helper method to set API key prefix for the first API key authentication. * * @param apiKeyPrefix API key prefix * @return a {@link ApiClient} object. */ 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 bearer token for the first Bearer authentication. * * @param bearerToken Bearer token * @return a {@link ApiClient} object. */ 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!"); } {{#hasOAuthMethods}} /** * Helper method to set access token for the first OAuth2 authentication. * * @param accessToken Access token * @return a {@link ApiClient} object. */ 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!"); } /** * Helper method to set the credentials for the first OAuth2 authentication. * * @param clientId the client ID * @param clientSecret the client secret * @return a {@link ApiClient} object. */ public ApiClient setOauthCredentials(String clientId, String clientSecret) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).setCredentials(clientId, clientSecret, isDebugging()); return this; } } throw new RuntimeException("No OAuth2 authentication configured!"); } /** * Helper method to set the credentials of a public client for the first OAuth2 authentication. * * @param clientId the client ID * @return a {@link ApiClient} object. */ public ApiClient setOauthCredentialsForPublicClient(String clientId) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).setCredentialsForPublicClient(clientId, isDebugging()); return this; } } throw new RuntimeException("No OAuth2 authentication configured!"); } /** * Helper method to set the password flow for the first OAuth2 authentication. * * @param username the user name * @param password the user password * @return a {@link ApiClient} object. */ public ApiClient setOauthPasswordFlow(String username, String password) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).usePasswordFlow(username, password); return this; } } throw new RuntimeException("No OAuth2 authentication configured!"); } /** * Helper method to set the authorization code flow for the first OAuth2 authentication. * * @param code the authorization code * @return a {@link ApiClient} object. */ public ApiClient setOauthAuthorizationCodeFlow(String code) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).useAuthorizationCodeFlow(code); return this; } } throw new RuntimeException("No OAuth2 authentication configured!"); } /** * Helper method to set the scopes for the first OAuth2 authentication. * * @param scope the oauth scope * @return a {@link ApiClient} object. */ public ApiClient setOauthScope(String scope) { for (Authentication auth : authentications.values()) { if (auth instanceof OAuth) { ((OAuth) auth).setScope(scope); 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 Http user agent * @return a {@link ApiClient} object. */ public ApiClient setUserAgent(String userAgent) { this.userAgent = userAgent; addDefaultHeader("User-Agent", userAgent); return this; } /** * Get the User-Agent header's value. * * @return User-Agent string */ public String getUserAgent(){ return userAgent; } /** * Add a default header. * * @param key The header's key * @param value The header's value * @return a {@link ApiClient} object. */ 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 a {@link ApiClient} object. */ public ApiClient addDefaultCookie(String key, String value) { defaultCookieMap.put(key, value); return this; } /** * Gets the client config. * * @return Client config */ public ClientConfig getClientConfig() { return clientConfig; } /** * Set the client config. * * @param clientConfig Set the client config * @return a {@link ApiClient} object. */ public ApiClient setClientConfig(ClientConfig clientConfig) { this.clientConfig = clientConfig; // Rebuild HTTP Client according to the new "clientConfig" value. this.httpClient = buildHttpClient(); return this; } /** * Check that whether debugging is enabled for this API client. * * @return True if debugging is switched on */ public boolean isDebugging() { return debugging; } /** * Enable/disable debugging for this API client. * * @param debugging To enable (true) or disable (false) debugging * @return a {@link ApiClient} object. */ public ApiClient setDebugging(boolean debugging) { this.debugging = debugging; // Rebuild HTTP Client according to the new "debugging" value. this.httpClient = buildHttpClient(); 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. * * @return Temp folder path */ public String getTempFolderPath() { return tempFolderPath; } /** * Set temp folder path * * @param tempFolderPath Temp folder path * @return a {@link ApiClient} object. */ public ApiClient setTempFolderPath(String tempFolderPath) { this.tempFolderPath = tempFolderPath; 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 a {@link ApiClient} object. */ public ApiClient setConnectTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; httpClient.property(ClientProperties.CONNECT_TIMEOUT, connectionTimeout); return this; } /** * read timeout (in milliseconds). * * @return Read timeout */ public int getReadTimeout() { return readTimeout; } /** * Set the read timeout (in milliseconds). * A value of 0 means no timeout, otherwise values must be between 1 and * {@link Integer#MAX_VALUE}. * * @param readTimeout Read timeout in milliseconds * @return a {@link ApiClient} object. */ public ApiClient setReadTimeout(int readTimeout) { this.readTimeout = readTimeout; httpClient.property(ClientProperties.READ_TIMEOUT, readTimeout); 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 a {@link ApiClient} object. */ public ApiClient setDateFormat(DateFormat dateFormat) { this.dateFormat = dateFormat; // also set the date format for model (de)serialization with Date properties this.json.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); } } /* * Format to {@code Pair} objects. * * @param collectionFormat Collection format * @param name Name * @param value Value * @return List of pairs */ public List parameterToPairs(String collectionFormat, String name, Object value){ List params = new ArrayList<>(); // preconditions if (name == null || name.isEmpty() || value == null) return params; Collection valueCollection; if (value instanceof Collection) { valueCollection = (Collection) value; } else { params.add(new Pair(name, parameterToString(value))); return params; } if (valueCollection.isEmpty()){ return params; } // get the collection format (default: csv) String format = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat); // create the params based on the collection format if ("multi".equals(format)) { for (Object item : valueCollection) { params.add(new Pair(name, parameterToString(item))); } return params; } String delimiter = ","; if ("csv".equals(format)) { delimiter = ","; } else if ("ssv".equals(format)) { delimiter = " "; } else if ("tsv".equals(format)) { delimiter = "\t"; } else if ("pipes".equals(format)) { delimiter = "|"; } StringBuilder sb = new StringBuilder() ; for (Object item : valueCollection) { sb.append(delimiter); sb.append(parameterToString(item)); } params.add(new Pair(name, sb.substring(1))); 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 * "*{@literal /}*" is also considered JSON by this method. * * @param mime MIME * @return True if the MIME type is JSON */ public boolean isJsonMime(String mime) { return mime != null && (mime.equals("*/*") || JSON_MIME_PATTERN.matcher(mime).matches()); } /** * 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 == null || 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, * JSON will be used. */ public String selectHeaderContentType(String... contentTypes) { if (contentTypes == null || contentTypes.length == 0) { 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; } } /** * Serialize the given Java object into string entity according the given * Content-Type (only JSON is supported for now). * * @param obj Object * @param formParams Form parameters * @param contentType Context type * @return Entity * @throws ApiException API exception */ public Entity serialize(Object obj, Map formParams, String contentType, boolean isBodyNullable) throws ApiException { Entity entity; if (contentType.startsWith("multipart/form-data")) { MultiPart multiPart = new MultiPart(); for (Entry param: formParams.entrySet()) { if (param.getValue() instanceof Iterable) { ((Iterable)param.getValue()).forEach(v -> addParamToMultipart(v, param.getKey(), multiPart)); } else { addParamToMultipart(param.getValue(), param.getKey(), multiPart); } } entity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE); } else if (contentType.startsWith("application/x-www-form-urlencoded")) { Form form = new Form(); for (Entry param: formParams.entrySet()) { form.param(param.getKey(), parameterToString(param.getValue())); } entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE); } else { // We let jersey handle the serialization if (isBodyNullable) { // payload is nullable if (obj instanceof String) { entity = Entity.entity(obj == null ? "null" : "\"" + ((String)obj).replaceAll("\"", Matcher.quoteReplacement("\\\"")) + "\"", contentType); } else { entity = Entity.entity(obj == null ? "null" : obj, contentType); } } else { if (obj instanceof String) { entity = Entity.entity(obj == null ? "" : "\"" + ((String)obj).replaceAll("\"", Matcher.quoteReplacement("\\\"")) + "\"", contentType); } else { entity = Entity.entity(obj == null ? "" : obj, contentType); } } } return entity; } /** * Adds the object with the provided key to the MultiPart. * Based on the object type sets Content-Disposition and Content-Type. * * @param obj Object * @param key Key of the object * @param multiPart MultiPart to add the form param to */ private void addParamToMultipart(Object value, String key, MultiPart multiPart) { if (value instanceof File) { File file = (File) value; FormDataContentDisposition contentDisp = FormDataContentDisposition.name(key) .fileName(file.getName()).size(file.length()).build(); // Attempt to probe the content type for the file so that the form part is more correctly // and precisely identified, but fall back to application/octet-stream if that fails. MediaType type; try { type = MediaType.valueOf(Files.probeContentType(file.toPath())); } catch (IOException | IllegalArgumentException e) { type = MediaType.APPLICATION_OCTET_STREAM_TYPE; } multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, type)); } else { FormDataContentDisposition contentDisp = FormDataContentDisposition.name(key).build(); multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(value))); } } /** * Serialize the given Java object into string according the given * Content-Type (only JSON, HTTP form is supported for now). * * @param obj Object * @param formParams Form parameters * @param contentType Context type * @param isBodyNullable True if the body is nullable * @return String * @throws ApiException API exception */ public String serializeToString(Object obj, Map formParams, String contentType, boolean isBodyNullable) throws ApiException { try { if (contentType.startsWith("multipart/form-data")) { throw new ApiException("multipart/form-data not yet supported for serializeToString (http signature authentication)"); } else if (contentType.startsWith("application/x-www-form-urlencoded")) { String formString = ""; for (Entry param : formParams.entrySet()) { formString = param.getKey() + "=" + URLEncoder.encode(parameterToString(param.getValue()), "UTF-8") + "&"; } if (formString.length() == 0) { // empty string return formString; } else { return formString.substring(0, formString.length() - 1); } } else { if (isBodyNullable) { return obj == null ? "null" : json.getMapper().writeValueAsString(obj); } else { return obj == null ? "" : json.getMapper().writeValueAsString(obj); } } } catch (Exception ex) { throw new ApiException("Failed to perform serializeToString: " + ex.toString()); } } /** * Deserialize response body to Java object according to the Content-Type. * * @param Type * @param response Response * @param returnType Return type * @return Deserialize object * @throws ApiException API exception */ @SuppressWarnings("unchecked") public T deserialize(Response response, GenericType returnType) throws ApiException { if (response == null || returnType == null) { return null; } if ("byte[]".equals(returnType.toString())) { // Handle binary response (byte array). return (T) response.readEntity(byte[].class); } else if (returnType.getRawType() == File.class) { // Handle file downloading. T file = (T) downloadFileFromResponse(response); return file; } // read the entity stream multiple times response.bufferEntity(); return response.readEntity(returnType); } /** * Download file from the given response. * * @param response Response * @return File * @throws ApiException If fail to read file content from response and write to disk */ public File downloadFileFromResponse(Response response) throws ApiException { try { File file = prepareDownloadFile(response); Files.copy(response.readEntity(InputStream.class), file.toPath(), StandardCopyOption.REPLACE_EXISTING); return file; } catch (IOException e) { throw new ApiException(e); } } /** *

Prepare the file for download from the response.

* * @param response a {@link {{javaxPackage}}.ws.rs.core.Response} object. * @return a {@link java.io.File} object. * @throws java.io.IOException if any. */ public File prepareDownloadFile(Response response) throws IOException { String filename = null; String contentDisposition = (String) response.getHeaders().getFirst("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 = 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(); } /** * Invoke API by sending HTTP request with the given options. * * @param Type * @param operation The qualified name of the operation * @param path The sub-path of the HTTP URL * @param method The request method, one of "GET", "POST", "PUT", "HEAD" and "DELETE" * @param queryParams The query parameters * @param body The request body object * @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 The return type into which to deserialize the response * @param isBodyNullable True if the body is nullable * @return The response body in type of string * @throws ApiException API exception */ public ApiResponse invokeAPI( String operation, String path, String method, List queryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType, boolean isBodyNullable) throws ApiException { String targetURL; List serverConfigurations; if (serverIndex != null && (serverConfigurations = operationServers.get(operation)) != null) { int index = operationServerIndex.getOrDefault(operation, serverIndex).intValue(); Map variables = operationServerVariables.getOrDefault(operation, serverVariables); if (index < 0 || index >= serverConfigurations.size()) { throw new ArrayIndexOutOfBoundsException( String.format( "Invalid index %d when selecting the host settings. Must be less than %d", index, serverConfigurations.size())); } targetURL = serverConfigurations.get(index).URL(variables) + path; } else { targetURL = this.basePath + path; } // Not using `.target(targetURL).path(path)` below, // to support (constant) query string in `path`, e.g. "/posts?draft=1" WebTarget target = httpClient.target(targetURL); if (queryParams != null) { for (Pair queryParam : queryParams) { if (queryParam.getValue() != null) { target = target.queryParam(queryParam.getName(), escapeString(queryParam.getValue())); } } } Invocation.Builder invocationBuilder = target.request(); if (accept != null) { invocationBuilder = invocationBuilder.accept(accept); } for (Entry entry : cookieParams.entrySet()) { String value = entry.getValue(); if (value != null) { invocationBuilder = invocationBuilder.cookie(entry.getKey(), value); } } for (Entry entry : defaultCookieMap.entrySet()) { String value = entry.getValue(); if (value != null) { invocationBuilder = invocationBuilder.cookie(entry.getKey(), value); } } Entity entity = serialize(body, formParams, contentType, isBodyNullable); // put all headers in one place Map allHeaderParams = new HashMap<>(defaultHeaderMap); allHeaderParams.putAll(headerParams); if (authNames != null) { // update different parameters (e.g. headers) for authentication updateParamsForAuth( authNames, queryParams, allHeaderParams, cookieParams, {{#hasHttpSignatureMethods}} serializeToString(body, formParams, contentType, isBodyNullable), {{/hasHttpSignatureMethods}} {{^hasHttpSignatureMethods}} null, {{/hasHttpSignatureMethods}} method, target.getUri()); } for (Entry entry : allHeaderParams.entrySet()) { String value = entry.getValue(); if (value != null) { invocationBuilder = invocationBuilder.header(entry.getKey(), value); } } Response response = null; try { response = sendRequest(method, invocationBuilder, entity); final int statusCode = response.getStatusInfo().getStatusCode(); {{#hasOAuthMethods}} // If OAuth is used and a status 401 is received, renew the access token and retry the request if (authNames != null && statusCode == Status.UNAUTHORIZED.getStatusCode()) { for (String authName : authNames) { Authentication authentication = authentications.get(authName); if (authentication instanceof OAuth) { OAuth2AccessToken accessToken = ((OAuth) authentication).renewAccessToken(); if (accessToken != null) { invocationBuilder.header("Authorization", null); invocationBuilder.header("Authorization", "Bearer " + accessToken.getAccessToken()); response = sendRequest(method, invocationBuilder, entity); } break; } } } {{/hasOAuthMethods}} Map> responseHeaders = buildResponseHeaders(response); if (statusCode == Status.NO_CONTENT.getStatusCode()) { return new ApiResponse(statusCode, responseHeaders); } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) { if (returnType == null) { return new ApiResponse(statusCode, responseHeaders); } else { return new ApiResponse(statusCode, responseHeaders, deserialize(response, returnType)); } } else { String message = "error"; String respBody = null; if (response.hasEntity()) { try { respBody = String.valueOf(response.readEntity(String.class)); message = respBody; } catch (RuntimeException e) { // e.printStackTrace(); } } throw new ApiException( response.getStatus(), message, buildResponseHeaders(response), respBody); } } finally { try { response.close(); } catch (Exception e) { // it's not critical, since the response object is local in method invokeAPI; that's fine, // just continue } } } private Response sendRequest(String method, Invocation.Builder invocationBuilder, Entity entity) { Response response; if ("POST".equals(method)) { response = invocationBuilder.post(entity); } else if ("PUT".equals(method)) { response = invocationBuilder.put(entity); } else if ("DELETE".equals(method)) { if ("".equals(entity.getEntity())) { response = invocationBuilder.method("DELETE"); } else { response = invocationBuilder.method("DELETE", entity); } } else if ("PATCH".equals(method)) { response = invocationBuilder.method("PATCH", entity); } else { response = invocationBuilder.method(method); } return response; } /** * @deprecated Add qualified name of the operation as a first parameter. */ @Deprecated public ApiResponse invokeAPI(String path, String method, List queryParams, Object body, Map headerParams, Map cookieParams, Map formParams, String accept, String contentType, String[] authNames, GenericType returnType, boolean isBodyNullable) throws ApiException { return invokeAPI(null, path, method, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames, returnType, isBodyNullable); } /** * Build the Client used to make HTTP requests. * * @return Client */ protected Client buildHttpClient() { // recreate the client config to pickup changes clientConfig = getDefaultClientConfig(); ClientBuilder clientBuilder = ClientBuilder.newBuilder(); clientBuilder = clientBuilder.withConfig(clientConfig); customizeClientBuilder(clientBuilder); return clientBuilder.build(); } /** * Get the default client config. * * @return Client config */ public ClientConfig getDefaultClientConfig() { ClientConfig clientConfig = new ClientConfig(); clientConfig.register(MultiPartFeature.class); clientConfig.register(json); clientConfig.register(JacksonFeature.class); clientConfig.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true); // turn off compliance validation to be able to send payloads with DELETE calls clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); if (debugging) { clientConfig.register(new LoggingFeature(java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), java.util.logging.Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 1024*50 /* Log payloads up to 50K */)); clientConfig.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY, LoggingFeature.Verbosity.PAYLOAD_ANY); // Set logger to ALL java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME).setLevel(java.util.logging.Level.ALL); } else { // suppress warnings for payloads with DELETE calls: java.util.logging.Logger.getLogger("org.glassfish.jersey.client").setLevel(java.util.logging.Level.SEVERE); } return clientConfig; } /** * Customize the client builder. * * This method can be overridden to customize the API client. For example, this can be used to: * 1. Set the hostname verifier to be used by the client to verify the endpoint's hostname * against its identification information. * 2. Set the client-side key store. * 3. Set the SSL context that will be used when creating secured transport connections to * server endpoints from web targets created by the client instance that is using this SSL context. * 4. Set the client-side trust store. * * To completely disable certificate validation (at your own risk), you can * override this method and invoke disableCertificateValidation(clientBuilder). * * @param clientBuilder a {@link {{javaxPackage}}.ws.rs.client.ClientBuilder} object. */ protected void customizeClientBuilder(ClientBuilder clientBuilder) { // No-op extension point } /** * Disable X.509 certificate validation in TLS connections. * * Please note that trusting all certificates is extremely risky. * This may be useful in a development environment with self-signed certificates. * * @param clientBuilder a {@link {{javaxPackage}}.ws.rs.client.ClientBuilder} object. * @throws java.security.KeyManagementException if any. * @throws java.security.NoSuchAlgorithmException if any. */ protected void disableCertificateValidation(ClientBuilder clientBuilder) throws KeyManagementException, NoSuchAlgorithmException { TrustManager[] trustAllCerts = new X509TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); clientBuilder.sslContext(sslContext); } /** *

Build the response headers.

* * @param response a {@link {{javaxPackage}}.ws.rs.core.Response} object. * @return a {@link java.util.Map} of response headers. */ protected Map> buildResponseHeaders(Response response) { Map> responseHeaders = new HashMap<>(); for (Entry> entry: response.getHeaders().entrySet()) { List values = entry.getValue(); List headers = new ArrayList<>(); for (Object o : values) { headers.add(String.valueOf(o)); } responseHeaders.put(entry.getKey(), headers); } return responseHeaders; } /** * 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 method HTTP method (e.g. POST) * @param uri HTTP URI */ protected 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) { continue; } auth.applyToParams(queryParams, headerParams, cookieParams, payload, method, uri); } } }