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