github.com/phrase/openapi@v0.0.0-20240514140800-49e8a106740e/openapi-generator/templates/java/libraries/jersey2-experimental/ApiClient.mustache (about)

     1  package {{invokerPackage}};
     2  
     3  import javax.ws.rs.client.Client;
     4  import javax.ws.rs.client.ClientBuilder;
     5  import javax.ws.rs.client.Entity;
     6  import javax.ws.rs.client.Invocation;
     7  import javax.ws.rs.client.WebTarget;
     8  import javax.ws.rs.core.Form;
     9  import javax.ws.rs.core.GenericType;
    10  import javax.ws.rs.core.MediaType;
    11  import javax.ws.rs.core.Response;
    12  import javax.ws.rs.core.Response.Status;
    13  
    14  import org.glassfish.jersey.client.ClientConfig;
    15  import org.glassfish.jersey.client.ClientProperties;
    16  import org.glassfish.jersey.client.HttpUrlConnectorProvider;
    17  import org.glassfish.jersey.jackson.JacksonFeature;
    18  import org.glassfish.jersey.media.multipart.FormDataBodyPart;
    19  import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
    20  import org.glassfish.jersey.media.multipart.MultiPart;
    21  import org.glassfish.jersey.media.multipart.MultiPartFeature;
    22  
    23  import java.io.IOException;
    24  import java.io.InputStream;
    25  
    26  import java.net.URI;
    27  {{^supportJava6}}
    28  import java.nio.file.Files;
    29  import java.nio.file.StandardCopyOption;
    30  import org.glassfish.jersey.logging.LoggingFeature;
    31  {{/supportJava6}}
    32  {{#supportJava6}}
    33  import org.apache.commons.io.FileUtils;
    34  import org.glassfish.jersey.filter.LoggingFilter;
    35  {{/supportJava6}}
    36  import java.util.Collection;
    37  import java.util.Collections;
    38  import java.util.Map;
    39  import java.util.Map.Entry;
    40  import java.util.HashMap;
    41  import java.util.HashSet;
    42  import java.util.List;
    43  import java.util.Arrays;
    44  import java.util.ArrayList;
    45  import java.util.Date;
    46  import java.util.TimeZone;
    47  
    48  import java.net.URLEncoder;
    49  
    50  import java.io.File;
    51  import java.io.UnsupportedEncodingException;
    52  
    53  import java.text.DateFormat;
    54  import java.util.regex.Matcher;
    55  import java.util.regex.Pattern;
    56  
    57  import {{invokerPackage}}.auth.Authentication;
    58  import {{invokerPackage}}.auth.HttpBasicAuth;
    59  import {{invokerPackage}}.auth.HttpBearerAuth;
    60  import {{invokerPackage}}.auth.HttpSignatureAuth;
    61  import {{invokerPackage}}.auth.ApiKeyAuth;
    62  import {{invokerPackage}}.model.AbstractOpenApiSchema;
    63  
    64  {{#hasOAuthMethods}}
    65  import {{invokerPackage}}.auth.OAuth;
    66  {{/hasOAuthMethods}}
    67  
    68  {{>generatedAnnotation}}
    69  public class ApiClient {
    70    protected Map<String, String> defaultHeaderMap = new HashMap<String, String>();
    71    protected Map<String, String> defaultCookieMap = new HashMap<String, String>();
    72    protected String basePath = "{{{basePath}}}";
    73    protected List<ServerConfiguration> servers = new ArrayList<ServerConfiguration>({{#servers}}{{#-first}}Arrays.asList(
    74  {{/-first}}    new ServerConfiguration(
    75        "{{{url}}}",
    76        "{{{description}}}{{^description}}No description provided{{/description}}",
    77        new HashMap<String, ServerVariable>(){{#variables}}{{#-first}} {{
    78  {{/-first}}        put("{{{name}}}", new ServerVariable(
    79            "{{{description}}}{{^description}}No description provided{{/description}}",
    80            "{{{defaultValue}}}",
    81            new HashSet<String>(
    82            {{#enumValues}}
    83            {{#-first}}
    84              Arrays.asList(
    85            {{/-first}}
    86                "{{{.}}}"{{^-last}},{{/-last}}
    87            {{#-last}}
    88              )
    89            {{/-last}}
    90            {{/enumValues}}
    91            )
    92          ));
    93        {{#-last}}
    94        }}{{/-last}}{{/variables}}
    95      ){{^-last}},{{/-last}}
    96    {{#-last}}
    97    ){{/-last}}{{/servers}});
    98    protected Integer serverIndex = 0;
    99    protected Map<String, String> serverVariables = null;
   100    protected Map<String, List<ServerConfiguration>> operationServers = new HashMap<String, List<ServerConfiguration>>() {{
   101      {{#apiInfo}}
   102      {{#apis}}
   103      {{#operations}}
   104      {{#operation}}
   105      {{#servers}}
   106      {{#-first}}
   107      put("{{{classname}}}.{{{operationId}}}", new ArrayList<ServerConfiguration>(Arrays.asList(
   108      {{/-first}}
   109        new ServerConfiguration(
   110          "{{{url}}}",
   111          "{{{description}}}{{^description}}No description provided{{/description}}",
   112          new HashMap<String, ServerVariable>(){{#variables}}{{#-first}} {{
   113  {{/-first}}          put("{{{name}}}", new ServerVariable(
   114              "{{{description}}}{{^description}}No description provided{{/description}}",
   115              "{{{defaultValue}}}",
   116              new HashSet<String>(
   117              {{#enumValues}}
   118              {{#-first}}
   119                Arrays.asList(
   120              {{/-first}}
   121                  "{{{.}}}"{{^-last}},{{/-last}}
   122              {{#-last}}
   123                )
   124              {{/-last}}
   125              {{/enumValues}}
   126              )
   127            ));
   128          {{#-last}}
   129          }}{{/-last}}{{/variables}}
   130        ){{^-last}},{{/-last}}
   131      {{#-last}}
   132      )));{{/-last}}
   133      {{/servers}}
   134      {{/operation}}
   135      {{/operations}}
   136      {{/apis}}
   137      {{/apiInfo}}
   138    }};
   139    protected Map<String, Integer> operationServerIndex = new HashMap<String, Integer>();
   140    protected Map<String, Map<String, String>> operationServerVariables = new HashMap<String, Map<String, String>>();
   141    protected boolean debugging = false;
   142    protected int connectionTimeout = 0;
   143    private int readTimeout = 0;
   144  
   145    protected Client httpClient;
   146    protected JSON json;
   147    protected String tempFolderPath = null;
   148  
   149    protected Map<String, Authentication> authentications;
   150    protected Map<String, String> authenticationLookup;
   151  
   152    protected DateFormat dateFormat;
   153  
   154    public ApiClient() {
   155      json = new JSON();
   156      httpClient = buildHttpClient(debugging);
   157  
   158      this.dateFormat = new RFC3339DateFormat();
   159  
   160      // Set default User-Agent.
   161      setUserAgent("{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{{artifactVersion}}}/java{{/httpUserAgent}}");
   162  
   163      // Setup authentications (key: authentication name, value: authentication).
   164      authentications = new HashMap<String, Authentication>();
   165      {{#authMethods}}
   166      {{#isBasic}}
   167      {{#isBasicBasic}}
   168      authentications.put("{{name}}", new HttpBasicAuth());
   169      {{/isBasicBasic}}
   170      {{#isBasicBearer}}
   171      authentications.put("{{name}}", new HttpBearerAuth("{{scheme}}"));
   172      {{/isBasicBearer}}
   173      {{#isHttpSignature}}
   174      authentications.put("{{name}}", new HttpSignatureAuth("{{name}}", null, null));
   175      {{/isHttpSignature}}
   176      {{/isBasic}}
   177      {{#isApiKey}}
   178      authentications.put("{{name}}", new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}"));
   179      {{/isApiKey}}
   180      {{#isOAuth}}
   181      authentications.put("{{name}}", new OAuth());
   182      {{/isOAuth}}
   183      {{/authMethods}}
   184      // Prevent the authentications from being modified.
   185      authentications = Collections.unmodifiableMap(authentications);
   186  
   187      // Setup authentication lookup (key: authentication alias, value: authentication name)
   188      authenticationLookup = new HashMap<String, String>();{{#authMethods}}{{#vendorExtensions.x-auth-id-alias}}
   189      authenticationLookup.put("{{name}}", "{{.}}");{{/vendorExtensions.x-auth-id-alias}}{{/authMethods}}
   190    }
   191  
   192    /**
   193     * Gets the JSON instance to do JSON serialization and deserialization.
   194     * @return JSON
   195     */
   196    public JSON getJSON() {
   197      return json;
   198    }
   199  
   200    public Client getHttpClient() {
   201      return httpClient;
   202    }
   203  
   204    public ApiClient setHttpClient(Client httpClient) {
   205      this.httpClient = httpClient;
   206      return this;
   207    }
   208  
   209    public String getBasePath() {
   210      return basePath;
   211    }
   212  
   213    public ApiClient setBasePath(String basePath) {
   214      this.basePath = basePath;
   215      return this;
   216    }
   217  
   218    public List<ServerConfiguration> getServers() {
   219      return servers;
   220    }
   221  
   222    public ApiClient setServers(List<ServerConfiguration> servers) {
   223      this.servers = servers;
   224      return this;
   225    }
   226  
   227    public Integer getServerIndex() {
   228      return serverIndex;
   229    }
   230  
   231    public ApiClient setServerIndex(Integer serverIndex) {
   232      this.serverIndex = serverIndex;
   233      return this;
   234    }
   235  
   236    public Map<String, String> getServerVariables() {
   237      return serverVariables;
   238    }
   239  
   240    public ApiClient setServerVariables(Map<String, String> serverVariables) {
   241      this.serverVariables = serverVariables;
   242      return this;
   243    }
   244  
   245    /**
   246     * Get authentications (key: authentication name, value: authentication).
   247     * @return Map of authentication object
   248     */
   249    public Map<String, Authentication> getAuthentications() {
   250      return authentications;
   251    }
   252  
   253    /**
   254     * Get authentication for the given name.
   255     *
   256     * @param authName The authentication name
   257     * @return The authentication, null if not found
   258     */
   259    public Authentication getAuthentication(String authName) {
   260      return authentications.get(authName);
   261    }
   262  
   263    /**
   264     * Helper method to set username for the first HTTP basic authentication.
   265     * @param username Username
   266     */
   267    public void setUsername(String username) {
   268      for (Authentication auth : authentications.values()) {
   269        if (auth instanceof HttpBasicAuth) {
   270          ((HttpBasicAuth) auth).setUsername(username);
   271          return;
   272        }
   273      }
   274      throw new RuntimeException("No HTTP basic authentication configured!");
   275    }
   276  
   277    /**
   278     * Helper method to set password for the first HTTP basic authentication.
   279     * @param password Password
   280     */
   281    public void setPassword(String password) {
   282      for (Authentication auth : authentications.values()) {
   283        if (auth instanceof HttpBasicAuth) {
   284          ((HttpBasicAuth) auth).setPassword(password);
   285          return;
   286        }
   287      }
   288      throw new RuntimeException("No HTTP basic authentication configured!");
   289    }
   290  
   291    /**
   292     * Helper method to set API key value for the first API key authentication.
   293     * @param apiKey API key
   294     */
   295    public void setApiKey(String apiKey) {
   296      for (Authentication auth : authentications.values()) {
   297        if (auth instanceof ApiKeyAuth) {
   298          ((ApiKeyAuth) auth).setApiKey(apiKey);
   299          return;
   300        }
   301      }
   302      throw new RuntimeException("No API key authentication configured!");
   303    }
   304  
   305    /**
   306     * Helper method to configure authentications which respects aliases of API keys.
   307     *
   308     * @param secrets Hash map from authentication name to its secret.
   309     */
   310    public void configureApiKeys(HashMap<String, String> secrets) {
   311      for (Map.Entry<String, Authentication> authEntry : authentications.entrySet()) {
   312        Authentication auth = authEntry.getValue();
   313        if (auth instanceof ApiKeyAuth) {
   314          String name = authEntry.getKey();
   315          // respect x-auth-id-alias property
   316          name = authenticationLookup.getOrDefault(name, name);
   317          if (secrets.containsKey(name)) {
   318            ((ApiKeyAuth) auth).setApiKey(secrets.get(name));
   319          }
   320        }
   321      }
   322    }
   323  
   324    /**
   325     * Helper method to set API key prefix for the first API key authentication.
   326     * @param apiKeyPrefix API key prefix
   327     */
   328    public void setApiKeyPrefix(String apiKeyPrefix) {
   329      for (Authentication auth : authentications.values()) {
   330        if (auth instanceof ApiKeyAuth) {
   331          ((ApiKeyAuth) auth).setApiKeyPrefix(apiKeyPrefix);
   332          return;
   333        }
   334      }
   335      throw new RuntimeException("No API key authentication configured!");
   336    }
   337  
   338    /**
   339     * Helper method to set bearer token for the first Bearer authentication.
   340     * @param bearerToken Bearer token
   341     */
   342    public void setBearerToken(String bearerToken) {
   343      for (Authentication auth : authentications.values()) {
   344        if (auth instanceof HttpBearerAuth) {
   345          ((HttpBearerAuth) auth).setBearerToken(bearerToken);
   346          return;
   347        }
   348      }
   349      throw new RuntimeException("No Bearer authentication configured!");
   350    }
   351  
   352    {{#hasOAuthMethods}}
   353    /**
   354     * Helper method to set access token for the first OAuth2 authentication.
   355     * @param accessToken Access token
   356     */
   357    public void setAccessToken(String accessToken) {
   358      for (Authentication auth : authentications.values()) {
   359        if (auth instanceof OAuth) {
   360          ((OAuth) auth).setAccessToken(accessToken);
   361          return;
   362        }
   363      }
   364      throw new RuntimeException("No OAuth2 authentication configured!");
   365    }
   366  
   367    {{/hasOAuthMethods}}
   368    /**
   369     * Set the User-Agent header's value (by adding to the default header map).
   370     * @param userAgent Http user agent
   371     * @return API client
   372     */
   373    public ApiClient setUserAgent(String userAgent) {
   374      addDefaultHeader("User-Agent", userAgent);
   375      return this;
   376    }
   377  
   378    /**
   379     * Add a default header.
   380     *
   381     * @param key The header's key
   382     * @param value The header's value
   383     * @return API client
   384     */
   385    public ApiClient addDefaultHeader(String key, String value) {
   386      defaultHeaderMap.put(key, value);
   387      return this;
   388    }
   389  
   390    /**
   391     * Add a default cookie.
   392     *
   393     * @param key The cookie's key
   394     * @param value The cookie's value
   395     * @return API client
   396     */
   397    public ApiClient addDefaultCookie(String key, String value) {
   398      defaultCookieMap.put(key, value);
   399      return this;
   400    }
   401  
   402    /**
   403     * Check that whether debugging is enabled for this API client.
   404     * @return True if debugging is switched on
   405     */
   406    public boolean isDebugging() {
   407      return debugging;
   408    }
   409  
   410    /**
   411     * Enable/disable debugging for this API client.
   412     *
   413     * @param debugging To enable (true) or disable (false) debugging
   414     * @return API client
   415     */
   416    public ApiClient setDebugging(boolean debugging) {
   417      this.debugging = debugging;
   418      // Rebuild HTTP Client according to the new "debugging" value.
   419      this.httpClient = buildHttpClient(debugging);
   420      return this;
   421    }
   422  
   423    /**
   424     * The path of temporary folder used to store downloaded files from endpoints
   425     * with file response. The default value is <code>null</code>, i.e. using
   426     * the system's default tempopary folder.
   427     *
   428     * @return Temp folder path
   429     */
   430    public String getTempFolderPath() {
   431      return tempFolderPath;
   432    }
   433  
   434    /**
   435     * Set temp folder path
   436     * @param tempFolderPath Temp folder path
   437     * @return API client
   438     */
   439    public ApiClient setTempFolderPath(String tempFolderPath) {
   440      this.tempFolderPath = tempFolderPath;
   441      return this;
   442    }
   443  
   444    /**
   445     * Connect timeout (in milliseconds).
   446     * @return Connection timeout
   447     */
   448    public int getConnectTimeout() {
   449      return connectionTimeout;
   450    }
   451  
   452    /**
   453     * Set the connect timeout (in milliseconds).
   454     * A value of 0 means no timeout, otherwise values must be between 1 and
   455     * {@link Integer#MAX_VALUE}.
   456     * @param connectionTimeout Connection timeout in milliseconds
   457     * @return API client
   458     */
   459    public ApiClient setConnectTimeout(int connectionTimeout) {
   460      this.connectionTimeout = connectionTimeout;
   461      httpClient.property(ClientProperties.CONNECT_TIMEOUT, connectionTimeout);
   462      return this;
   463    }
   464  
   465    /**
   466     * read timeout (in milliseconds).
   467     * @return Read timeout
   468     */
   469    public int getReadTimeout() {
   470      return readTimeout;
   471    }
   472  
   473    /**
   474     * Set the read timeout (in milliseconds).
   475     * A value of 0 means no timeout, otherwise values must be between 1 and
   476     * {@link Integer#MAX_VALUE}.
   477     * @param readTimeout Read timeout in milliseconds
   478     * @return API client
   479     */
   480    public ApiClient setReadTimeout(int readTimeout) {
   481      this.readTimeout = readTimeout;
   482      httpClient.property(ClientProperties.READ_TIMEOUT, readTimeout);
   483      return this;
   484    }
   485  
   486    /**
   487     * Get the date format used to parse/format date parameters.
   488     * @return Date format
   489     */
   490    public DateFormat getDateFormat() {
   491      return dateFormat;
   492    }
   493  
   494    /**
   495     * Set the date format used to parse/format date parameters.
   496     * @param dateFormat Date format
   497     * @return API client
   498     */
   499    public ApiClient setDateFormat(DateFormat dateFormat) {
   500      this.dateFormat = dateFormat;
   501      // also set the date format for model (de)serialization with Date properties
   502      this.json.setDateFormat((DateFormat) dateFormat.clone());
   503      return this;
   504    }
   505  
   506    /**
   507     * Parse the given string into Date object.
   508     * @param str String
   509     * @return Date
   510     */
   511    public Date parseDate(String str) {
   512      try {
   513        return dateFormat.parse(str);
   514      } catch (java.text.ParseException e) {
   515        throw new RuntimeException(e);
   516      }
   517    }
   518  
   519    /**
   520     * Format the given Date object into string.
   521     * @param date Date
   522     * @return Date in string format
   523     */
   524    public String formatDate(Date date) {
   525      return dateFormat.format(date);
   526    }
   527  
   528    /**
   529     * Format the given parameter object into string.
   530     * @param param Object
   531     * @return Object in string format
   532     */
   533    public String parameterToString(Object param) {
   534      if (param == null) {
   535        return "";
   536      } else if (param instanceof Date) {
   537        return formatDate((Date) param);
   538      } else if (param instanceof Collection) {
   539        StringBuilder b = new StringBuilder();
   540        for(Object o : (Collection)param) {
   541          if(b.length() > 0) {
   542            b.append(',');
   543          }
   544          b.append(String.valueOf(o));
   545        }
   546        return b.toString();
   547      } else {
   548        return String.valueOf(param);
   549      }
   550    }
   551  
   552    /*
   553     * Format to {@code Pair} objects.
   554     * @param collectionFormat Collection format
   555     * @param name Name
   556     * @param value Value
   557     * @return List of pairs
   558     */
   559    public List<Pair> parameterToPairs(String collectionFormat, String name, Object value){
   560      List<Pair> params = new ArrayList<Pair>();
   561  
   562      // preconditions
   563      if (name == null || name.isEmpty() || value == null) return params;
   564  
   565      Collection valueCollection;
   566      if (value instanceof Collection) {
   567        valueCollection = (Collection) value;
   568      } else {
   569        params.add(new Pair(name, parameterToString(value)));
   570        return params;
   571      }
   572  
   573      if (valueCollection.isEmpty()){
   574        return params;
   575      }
   576  
   577      // get the collection format (default: csv)
   578      String format = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat);
   579  
   580      // create the params based on the collection format
   581      if ("multi".equals(format)) {
   582        for (Object item : valueCollection) {
   583          params.add(new Pair(name, parameterToString(item)));
   584        }
   585  
   586        return params;
   587      }
   588  
   589      String delimiter = ",";
   590  
   591      if ("csv".equals(format)) {
   592        delimiter = ",";
   593      } else if ("ssv".equals(format)) {
   594        delimiter = " ";
   595      } else if ("tsv".equals(format)) {
   596        delimiter = "\t";
   597      } else if ("pipes".equals(format)) {
   598        delimiter = "|";
   599      }
   600  
   601      StringBuilder sb = new StringBuilder() ;
   602      for (Object item : valueCollection) {
   603        sb.append(delimiter);
   604        sb.append(parameterToString(item));
   605      }
   606  
   607      params.add(new Pair(name, sb.substring(1)));
   608  
   609      return params;
   610    }
   611  
   612    /**
   613     * Check if the given MIME is a JSON MIME.
   614     * JSON MIME examples:
   615     *   application/json
   616     *   application/json; charset=UTF8
   617     *   APPLICATION/JSON
   618     *   application/vnd.company+json
   619     * "* / *" is also default to JSON
   620     * @param mime MIME
   621     * @return True if the MIME type is JSON
   622     */
   623    public boolean isJsonMime(String mime) {
   624      String jsonMime = "(?i)^(application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
   625      return mime != null && (mime.matches(jsonMime) || mime.equals("*/*"));
   626    }
   627  
   628    /**
   629     * Select the Accept header's value from the given accepts array:
   630     *   if JSON exists in the given array, use it;
   631     *   otherwise use all of them (joining into a string)
   632     *
   633     * @param accepts The accepts array to select from
   634     * @return The Accept header to use. If the given array is empty,
   635     *   null will be returned (not to set the Accept header explicitly).
   636     */
   637    public String selectHeaderAccept(String[] accepts) {
   638      if (accepts.length == 0) {
   639        return null;
   640      }
   641      for (String accept : accepts) {
   642        if (isJsonMime(accept)) {
   643          return accept;
   644        }
   645      }
   646      return StringUtil.join(accepts, ",");
   647    }
   648  
   649    /**
   650     * Select the Content-Type header's value from the given array:
   651     *   if JSON exists in the given array, use it;
   652     *   otherwise use the first one of the array.
   653     *
   654     * @param contentTypes The Content-Type array to select from
   655     * @return The Content-Type header to use. If the given array is empty,
   656     *   JSON will be used.
   657     */
   658    public String selectHeaderContentType(String[] contentTypes) {
   659      if (contentTypes.length == 0) {
   660        return "application/json";
   661      }
   662      for (String contentType : contentTypes) {
   663        if (isJsonMime(contentType)) {
   664          return contentType;
   665        }
   666      }
   667      return contentTypes[0];
   668    }
   669  
   670    /**
   671     * Escape the given string to be used as URL query value.
   672     * @param str String
   673     * @return Escaped string
   674     */
   675    public String escapeString(String str) {
   676      try {
   677        return URLEncoder.encode(str, "utf8").replaceAll("\\+", "%20");
   678      } catch (UnsupportedEncodingException e) {
   679        return str;
   680      }
   681    }
   682  
   683    /**
   684     * Serialize the given Java object into string entity according the given
   685     * Content-Type (only JSON is supported for now).
   686     * @param obj Object
   687     * @param formParams Form parameters
   688     * @param contentType Context type
   689     * @return Entity
   690     * @throws ApiException API exception
   691     */
   692    public Entity<?> serialize(Object obj, Map<String, Object> formParams, String contentType) throws ApiException {
   693      Entity<?> entity;
   694      if (contentType.startsWith("multipart/form-data")) {
   695        MultiPart multiPart = new MultiPart();
   696        for (Entry<String, Object> param: formParams.entrySet()) {
   697          if (param.getValue() instanceof File) {
   698            File file = (File) param.getValue();
   699            FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey())
   700                .fileName(file.getName()).size(file.length()).build();
   701            multiPart.bodyPart(new FormDataBodyPart(contentDisp, file, MediaType.APPLICATION_OCTET_STREAM_TYPE));
   702          } else {
   703            FormDataContentDisposition contentDisp = FormDataContentDisposition.name(param.getKey()).build();
   704            multiPart.bodyPart(new FormDataBodyPart(contentDisp, parameterToString(param.getValue())));
   705          }
   706        }
   707        entity = Entity.entity(multiPart, MediaType.MULTIPART_FORM_DATA_TYPE);
   708      } else if (contentType.startsWith("application/x-www-form-urlencoded")) {
   709        Form form = new Form();
   710        for (Entry<String, Object> param: formParams.entrySet()) {
   711          form.param(param.getKey(), parameterToString(param.getValue()));
   712        }
   713        entity = Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE);
   714      } else {
   715        // We let jersey handle the serialization
   716        entity = Entity.entity(obj == null ? Entity.text("") : obj, contentType);
   717      }
   718      return entity;
   719    }
   720  
   721    /**
   722     * Serialize the given Java object into string according the given
   723     * Content-Type (only JSON, HTTP form is supported for now).
   724     * @param obj Object
   725     * @param formParams Form parameters
   726     * @param contentType Context type
   727     * @return String
   728     * @throws ApiException API exception
   729     */
   730    public String serializeToString(Object obj, Map<String, Object> formParams, String contentType) throws ApiException {
   731      try {
   732        if (contentType.startsWith("multipart/form-data")) {
   733          throw new ApiException("multipart/form-data not yet supported for serializeToString (http signature authentication)");
   734        } else if (contentType.startsWith("application/x-www-form-urlencoded")) {
   735          String formString = "";
   736          for (Entry<String, Object> param : formParams.entrySet()) {
   737            formString = param.getKey() + "=" + URLEncoder.encode(parameterToString(param.getValue()), "UTF-8") + "&";
   738          }
   739  
   740          if (formString.length() == 0) { // empty string
   741            return formString;
   742          } else {
   743            return formString.substring(0, formString.length() - 1);
   744          }
   745        } else {
   746          return json.getMapper().writeValueAsString(obj);
   747        }
   748      } catch (Exception ex) {
   749        throw new ApiException("Failed to perform serializeToString: " + ex.toString());
   750      }
   751    }
   752  
   753    public AbstractOpenApiSchema deserializeSchemas(Response response, AbstractOpenApiSchema schema) throws ApiException{
   754  
   755      Object result = null;
   756      int matchCounter = 0;
   757      ArrayList<String> matchSchemas = new ArrayList<>();
   758  
   759      for (Map.Entry<String, GenericType> entry : schema.getSchemas().entrySet()) {
   760        String schemaName = entry.getKey();
   761        GenericType schemaType = entry.getValue();
   762  
   763        if (schemaType instanceof GenericType) { // model
   764          try {
   765            Object deserializedObject = deserialize(response, schemaType);
   766            if (deserializedObject != null) {
   767              result = deserializedObject;
   768              matchCounter++;
   769  
   770              if ("anyOf".equals(schema.getSchemaType())) {
   771                break;
   772              } else if ("oneOf".equals(schema.getSchemaType())) {
   773                matchSchemas.add(schemaName);
   774              } else {
   775                throw new ApiException("Unknowe type found while expecting anyOf/oneOf:" + schema.getSchemaType());
   776              }
   777            } else {
   778              // failed to deserialize the response in the schema provided, proceed to the next one if any
   779            }
   780          } catch (Exception ex) {
   781            // failed to deserialize, do nothing and try next one (schema)
   782          }
   783        } else {// unknown type
   784          throw new ApiException(schemaType.getClass() + " is not a GenericType and cannot be handled properly in deserialization.");
   785        }
   786  
   787      }
   788  
   789      if (matchCounter > 1 && "oneOf".equals(schema.getSchemaType())) {// more than 1 match for oneOf
   790        throw new ApiException("Response body is invalid as it matches more than one schema (" + String.join(", ", matchSchemas) + ") defined in the oneOf model: " + schema.getClass().getName());
   791      } else if (matchCounter == 0) { // fail to match any in oneOf/anyOf schemas
   792        throw new ApiException("Response body is invalid as it doens't match any schemas (" + String.join(", ", schema.getSchemas().keySet()) + ") defined in the oneOf/anyOf model: " + schema.getClass().getName());
   793      } else { // only one matched
   794        schema.setActualInstance(result);
   795        return schema;
   796      }
   797  
   798    }
   799  
   800  
   801  
   802    /**
   803     * Deserialize response body to Java object according to the Content-Type.
   804     * @param <T> Type
   805     * @param response Response
   806     * @param returnType Return type
   807     * @return Deserialize object
   808     * @throws ApiException API exception
   809     */
   810    @SuppressWarnings("unchecked")
   811    public <T> T deserialize(Response response, GenericType<T> returnType) throws ApiException {
   812      if (response == null || returnType == null) {
   813        return null;
   814      }
   815  
   816      if ("byte[]".equals(returnType.toString())) {
   817        // Handle binary response (byte array).
   818        return (T) response.readEntity(byte[].class);
   819      } else if (returnType.getRawType() == File.class) {
   820        // Handle file downloading.
   821        T file = (T) downloadFileFromResponse(response);
   822        return file;
   823      }
   824  
   825      String contentType = null;
   826      List<Object> contentTypes = response.getHeaders().get("Content-Type");
   827      if (contentTypes != null && !contentTypes.isEmpty())
   828        contentType = String.valueOf(contentTypes.get(0));
   829  
   830      // read the entity stream multiple times
   831      response.bufferEntity();
   832  
   833      return response.readEntity(returnType);
   834    }
   835  
   836    /**
   837     * Download file from the given response.
   838     * @param response Response
   839     * @return File
   840     * @throws ApiException If fail to read file content from response and write to disk
   841     */
   842    public File downloadFileFromResponse(Response response) throws ApiException {
   843      try {
   844        File file = prepareDownloadFile(response);
   845  {{^supportJava6}}
   846        Files.copy(response.readEntity(InputStream.class), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
   847  {{/supportJava6}}
   848  {{#supportJava6}}
   849        // Java6 falls back to commons.io for file copying
   850        FileUtils.copyToFile(response.readEntity(InputStream.class), file);
   851  {{/supportJava6}}
   852        return file;
   853      } catch (IOException e) {
   854        throw new ApiException(e);
   855      }
   856    }
   857  
   858    public File prepareDownloadFile(Response response) throws IOException {
   859      String filename = null;
   860      String contentDisposition = (String) response.getHeaders().getFirst("Content-Disposition");
   861      if (contentDisposition != null && !"".equals(contentDisposition)) {
   862        // Get filename from the Content-Disposition header.
   863        Pattern pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?");
   864        Matcher matcher = pattern.matcher(contentDisposition);
   865        if (matcher.find())
   866          filename = matcher.group(1);
   867      }
   868  
   869      String prefix;
   870      String suffix = null;
   871      if (filename == null) {
   872        prefix = "download-";
   873        suffix = "";
   874      } else {
   875        int pos = filename.lastIndexOf('.');
   876        if (pos == -1) {
   877          prefix = filename + "-";
   878        } else {
   879          prefix = filename.substring(0, pos) + "-";
   880          suffix = filename.substring(pos);
   881        }
   882        // File.createTempFile requires the prefix to be at least three characters long
   883        if (prefix.length() < 3)
   884          prefix = "download-";
   885      }
   886  
   887      if (tempFolderPath == null)
   888        return File.createTempFile(prefix, suffix);
   889      else
   890        return File.createTempFile(prefix, suffix, new File(tempFolderPath));
   891    }
   892  
   893    /**
   894     * Invoke API by sending HTTP request with the given options.
   895     *
   896     * @param <T> Type
   897     * @param operation The qualified name of the operation
   898     * @param path The sub-path of the HTTP URL
   899     * @param method The request method, one of "GET", "POST", "PUT", "HEAD" and "DELETE"
   900     * @param queryParams The query parameters
   901     * @param body The request body object
   902     * @param headerParams The header parameters
   903     * @param cookieParams The cookie parameters
   904     * @param formParams The form parameters
   905     * @param accept The request's Accept header
   906     * @param contentType The request's Content-Type header
   907     * @param authNames The authentications to apply
   908     * @param returnType The return type into which to deserialize the response
   909     * @param schema An instance of the response that uses oneOf/anyOf
   910     * @return The response body in type of string
   911     * @throws ApiException API exception
   912     */
   913    public <T> ApiResponse<T> invokeAPI(String operation, String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> cookieParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType, AbstractOpenApiSchema schema) throws ApiException {
   914  
   915      // Not using `.target(targetURL).path(path)` below,
   916      // to support (constant) query string in `path`, e.g. "/posts?draft=1"
   917      String targetURL;
   918      if (serverIndex != null) {
   919        Integer index;
   920        List<ServerConfiguration> serverConfigurations;
   921        Map<String, String> variables;
   922  
   923        if (operationServers.containsKey(operation)) {
   924          index = operationServerIndex.getOrDefault(operation, serverIndex);
   925          variables = operationServerVariables.getOrDefault(operation, serverVariables);
   926          serverConfigurations = operationServers.get(operation);
   927        } else {
   928          index = serverIndex;
   929          variables = serverVariables;
   930          serverConfigurations = servers;
   931        }
   932        if (index < 0 || index >= serverConfigurations.size()) {
   933          throw new ArrayIndexOutOfBoundsException(String.format(
   934            "Invalid index %d when selecting the host settings. Must be less than %d", index, serverConfigurations.size()
   935          ));
   936        }
   937        targetURL = serverConfigurations.get(index).URL(variables) + path;
   938      } else {
   939        targetURL = this.basePath + path;
   940      }
   941      WebTarget target = httpClient.target(targetURL);
   942  
   943      if (queryParams != null) {
   944        for (Pair queryParam : queryParams) {
   945          if (queryParam.getValue() != null) {
   946            target = target.queryParam(queryParam.getName(), escapeString(queryParam.getValue()));
   947          }
   948        }
   949      }
   950  
   951      Invocation.Builder invocationBuilder = target.request().accept(accept);
   952  
   953      for (Entry<String, String> entry : headerParams.entrySet()) {
   954        String value = entry.getValue();
   955        if (value != null) {
   956          invocationBuilder = invocationBuilder.header(entry.getKey(), value);
   957        }
   958      }
   959  
   960      for (Entry<String, String> entry : cookieParams.entrySet()) {
   961        String value = entry.getValue();
   962        if (value != null) {
   963          invocationBuilder = invocationBuilder.cookie(entry.getKey(), value);
   964        }
   965      }
   966  
   967      for (Entry<String, String> entry : defaultCookieMap.entrySet()) {
   968        String value = entry.getValue();
   969        if (value != null) {
   970          invocationBuilder = invocationBuilder.cookie(entry.getKey(), value);
   971        }
   972      }
   973  
   974      for (Entry<String, String> entry : defaultHeaderMap.entrySet()) {
   975        String key = entry.getKey();
   976        if (!headerParams.containsKey(key)) {
   977          String value = entry.getValue();
   978          if (value != null) {
   979            invocationBuilder = invocationBuilder.header(key, value);
   980          }
   981        }
   982      }
   983  
   984      Entity<?> entity = serialize(body, formParams, contentType);
   985  
   986      // put all headers in one place
   987      Map<String, String> allHeaderParams = new HashMap<>();
   988      allHeaderParams.putAll(defaultHeaderMap);
   989      allHeaderParams.putAll(headerParams);
   990     
   991      // update different parameters (e.g. headers) for authentication
   992      updateParamsForAuth(authNames, queryParams, allHeaderParams, cookieParams, serializeToString(body, formParams, contentType), method, target.getUri());
   993  
   994      Response response = null;
   995  
   996      try {
   997        if ("GET".equals(method)) {
   998          response = invocationBuilder.get();
   999        } else if ("POST".equals(method)) {
  1000          response = invocationBuilder.post(entity);
  1001        } else if ("PUT".equals(method)) {
  1002          response = invocationBuilder.put(entity);
  1003        } else if ("DELETE".equals(method)) {
  1004          response = invocationBuilder.method("DELETE", entity);
  1005        } else if ("PATCH".equals(method)) {
  1006          response = invocationBuilder.method("PATCH", entity);
  1007        } else if ("HEAD".equals(method)) {
  1008          response = invocationBuilder.head();
  1009        } else if ("OPTIONS".equals(method)) {
  1010          response = invocationBuilder.options();
  1011        } else if ("TRACE".equals(method)) {
  1012          response = invocationBuilder.trace();
  1013        } else {
  1014          throw new ApiException(500, "unknown method type " + method);
  1015        }
  1016  
  1017        int statusCode = response.getStatusInfo().getStatusCode();
  1018        Map<String, List<String>> responseHeaders = buildResponseHeaders(response);
  1019  
  1020        if (response.getStatus() == Status.NO_CONTENT.getStatusCode()) {
  1021          return new ApiResponse<{{#supportJava6}}T{{/supportJava6}}>(statusCode, responseHeaders);
  1022        } else if (response.getStatusInfo().getFamily() == Status.Family.SUCCESSFUL) {
  1023          if (returnType == null)
  1024            return new ApiResponse<{{#supportJava6}}T{{/supportJava6}}>(statusCode, responseHeaders);
  1025          else
  1026            if (schema == null) {
  1027              return new ApiResponse<>(statusCode, responseHeaders, deserialize(response, returnType));
  1028            } else { // oneOf/anyOf
  1029              return new ApiResponse<>(statusCode, responseHeaders, (T)deserializeSchemas(response, schema));
  1030            }
  1031        } else {
  1032          String message = "error";
  1033          String respBody = null;
  1034          if (response.hasEntity()) {
  1035            try {
  1036              respBody = String.valueOf(response.readEntity(String.class));
  1037              message = respBody;
  1038            } catch (RuntimeException e) {
  1039              // e.printStackTrace();
  1040            }
  1041          }
  1042          throw new ApiException(
  1043            response.getStatus(),
  1044            message,
  1045            buildResponseHeaders(response),
  1046            respBody);
  1047        }
  1048      } finally {
  1049        try {
  1050          response.close();
  1051        } catch (Exception e) {
  1052          // it's not critical, since the response object is local in method invokeAPI; that's fine, just continue
  1053        }
  1054      }
  1055    }
  1056  
  1057    /**
  1058     * @deprecated Add qualified name of the operation as a first parameter.
  1059     */
  1060    @Deprecated
  1061    public <T> ApiResponse<T> invokeAPI(String path, String method, List<Pair> queryParams, Object body, Map<String, String> headerParams, Map<String, String> cookieParams, Map<String, Object> formParams, String accept, String contentType, String[] authNames, GenericType<T> returnType, AbstractOpenApiSchema schema) throws ApiException {
  1062      return invokeAPI(null, path, method, queryParams, body, headerParams, cookieParams, formParams, accept, contentType, authNames, returnType, schema);
  1063    }
  1064  
  1065    /**
  1066     * Build the Client used to make HTTP requests.
  1067     * @param debugging Debug setting
  1068     * @return Client
  1069     */
  1070    protected Client buildHttpClient(boolean debugging) {
  1071      final ClientConfig clientConfig = new ClientConfig();
  1072      clientConfig.register(MultiPartFeature.class);
  1073      clientConfig.register(json);
  1074      clientConfig.register(JacksonFeature.class);
  1075      clientConfig.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true);
  1076      // turn off compliance validation to be able to send payloads with DELETE calls
  1077      clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
  1078      if (debugging) {
  1079  {{^supportJava6}}
  1080        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 */));
  1081        clientConfig.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY, LoggingFeature.Verbosity.PAYLOAD_ANY);
  1082        // Set logger to ALL
  1083        java.util.logging.Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME).setLevel(java.util.logging.Level.ALL);
  1084  {{/supportJava6}}
  1085  {{#supportJava6}}
  1086        clientConfig.register(new LoggingFilter(java.util.logging.Logger.getLogger(LoggingFilter.class.getName()), true));
  1087  {{/supportJava6}}
  1088      } else {
  1089        // suppress warnings for payloads with DELETE calls:
  1090        java.util.logging.Logger.getLogger("org.glassfish.jersey.client").setLevel(java.util.logging.Level.SEVERE);
  1091      }
  1092      performAdditionalClientConfiguration(clientConfig);
  1093      return ClientBuilder.newClient(clientConfig);
  1094    }
  1095  
  1096    protected void performAdditionalClientConfiguration(ClientConfig clientConfig) {
  1097      // No-op extension point
  1098    }
  1099  
  1100    protected Map<String, List<String>> buildResponseHeaders(Response response) {
  1101      Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
  1102      for (Entry<String, List<Object>> entry: response.getHeaders().entrySet()) {
  1103        List<Object> values = entry.getValue();
  1104        List<String> headers = new ArrayList<String>();
  1105        for (Object o : values) {
  1106          headers.add(String.valueOf(o));
  1107        }
  1108        responseHeaders.put(entry.getKey(), headers);
  1109      }
  1110      return responseHeaders;
  1111    }
  1112  
  1113    /**
  1114     * Update query and header parameters based on authentication settings.
  1115     *
  1116     * @param authNames The authentications to apply
  1117     * @param queryParams List of query parameters
  1118     * @param headerParams Map of header parameters
  1119     * @param cookieParams Map of cookie parameters
  1120     * @param method HTTP method (e.g. POST)
  1121     * @param uri HTTP URI
  1122     */
  1123    protected void updateParamsForAuth(String[] authNames, List<Pair> queryParams, Map<String, String> headerParams,
  1124                                       Map<String, String> cookieParams, String payload, String method, URI uri) throws ApiException {
  1125      for (String authName : authNames) {
  1126        Authentication auth = authentications.get(authName);
  1127        if (auth == null) {
  1128          throw new RuntimeException("Authentication undefined: " + authName);
  1129        }
  1130        auth.applyToParams(queryParams, headerParams, cookieParams, payload, method, uri);
  1131      }
  1132    }
  1133  }