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 }