@@ -362,29 +362,6 @@ public ApiClient setDebugging(boolean debugging) {
362362 return this ;
363363 }
364364
365- /**
366- * The path of temporary folder used to store downloaded files from endpoints
367- * with file response. The default value is <code>null</code>, i.e. using
368- * the system's default tempopary folder.
369- *
370- * @see <a href="https://docs.oracle.com/javase/7/docs/api/java/io/File.html#createTempFile">createTempFile</a>
371- * @return Temporary folder path
372- */
373- public String getTempFolderPath () {
374- return tempFolderPath ;
375- }
376-
377- /**
378- * Set the temporary folder path (for downloading files)
379- *
380- * @param tempFolderPath Temporary folder path
381- * @return ApiClient
382- */
383- public ApiClient setTempFolderPath (String tempFolderPath ) {
384- this .tempFolderPath = tempFolderPath ;
385- return this ;
386- }
387-
388365 /**
389366 * Get connection timeout (in seconds).
390367 *
@@ -659,7 +636,7 @@ public <T> T deserialize(Response response, Type returnType) throws ApiException
659636 if (returnType .equals (MimeMultipart .class )) {
660637 try {
661638 InputStream in = response .body ().byteStream ();
662- ByteArrayDataSource dataSource = new ByteArrayDataSource (in , "multipart/form-data " );
639+ ByteArrayDataSource dataSource = new ByteArrayDataSource (in , "multipart/mixed " );
663640 return (T ) new MimeMultipart (dataSource );
664641 }
665642 catch (IOException | MessagingException e ) {
@@ -675,10 +652,6 @@ else if (returnType.equals(byte[].class)) {
675652 throw new ApiException (e );
676653 }
677654 }
678- else if (returnType .equals (File .class )) {
679- // Handle file downloading.
680- return (T ) downloadFileFromResponse (response );
681- }
682655
683656 String respBody ;
684657 try {
@@ -730,10 +703,6 @@ public RequestBody serialize(Object obj, String contentType) throws ApiException
730703 // Binary (byte array) body parameter support.
731704 return RequestBody .create (MediaType .parse (contentType ), (byte []) obj );
732705 }
733- else if (obj instanceof File ) {
734- // File body parameter support.
735- return RequestBody .create (MediaType .parse (contentType ), (File ) obj );
736- }
737706 else if (isJsonMime (contentType )) {
738707 String content ;
739708 if (obj != null ) {
@@ -749,127 +718,38 @@ else if (isJsonMime(contentType)) {
749718 }
750719 }
751720
752- /**
753- * Download file from the given response.
754- *
755- * @param response An instance of the Response object
756- * @throws ApiException If fail to read file content from response and write to disk
757- * @return Downloaded file
758- */
759- public File downloadFileFromResponse (Response response ) throws ApiException {
760- try {
761- File file = prepareDownloadFile (response );
762- BufferedSink sink = Okio .buffer (Okio .sink (file ));
763- sink .writeAll (response .body ().source ());
764- sink .close ();
765- return file ;
766- }
767- catch (IOException e ) {
768- throw new ApiException (e );
769- }
770- }
771-
772- /**
773- * Prepare file for download
774- *
775- * @param response An instance of the Response object
776- * @throws IOException If fail to prepare file for download
777- * @return Prepared file for the download
778- */
779- public File prepareDownloadFile (Response response ) throws IOException {
780- String filename = null ;
781- String contentDisposition = response .header ("Content-Disposition" );
782- if (contentDisposition != null && !"" .equals (contentDisposition )) {
783- // Get filename from the Content-Disposition header.
784- Pattern pattern = Pattern .compile ("filename=['\" ]?([^'\" \\ s]+)['\" ]?" );
785- Matcher matcher = pattern .matcher (contentDisposition );
786- if (matcher .find ()) {
787- filename = sanitizeFilename (matcher .group (1 ));
788- }
789- }
790-
791- String prefix = null ;
792- String suffix = null ;
793- if (filename == null ) {
794- prefix = "download-" ;
795- suffix = "" ;
796- }
797- else {
798- int pos = filename .lastIndexOf ("." );
799- if (pos == -1 ) {
800- prefix = filename + "-" ;
801- }
802- else {
803- prefix = filename .substring (0 , pos ) + "-" ;
804- suffix = filename .substring (pos );
805- }
806- // File.createTempFile requires the prefix to be at least three characters long
807- if (prefix .length () < 3 )
808- prefix = "download-" ;
809- }
810-
811- if (tempFolderPath == null )
812- return File .createTempFile (prefix , suffix );
813- else
814- return File .createTempFile (prefix , suffix , new File (tempFolderPath ));
815- }
816-
817- /**
818- * {@link #execute(Call, Type)}
819- *
820- * @param <T> Type
821- * @param call An instance of the Call object
822- * @throws ApiException If fail to execute the call
823- * @return ApiResponse<T>
824- */
825- public <T > ApiResponse <T > execute (Call call ) throws ApiException {
826- return execute (call , null );
827- }
828-
829721 /**
830722 * Execute HTTP call and deserialize the HTTP response body into the given return type.
831723 *
832- * @param returnType The return type used to deserialize HTTP response body
833724 * @param <T> The return type corresponding to (same with) returnType
834725 * @param call Call
726+ * @param request Request
835727 * @return ApiResponse object containing response status, headers and
836728 * data, which is a Java object deserialized from response body and would be null
837729 * when returnType is null.
838730 * @throws ApiException If fail to execute the call
839731 */
840- public <T > ApiResponse <T > execute (Call call , Type returnType ) throws ApiException {
732+ public <T > ApiResponse <T > execute (Call call , RequestIfc request ) throws ApiException {
841733 try {
842734 Response response = call .execute ();
843- T data = handleResponse (response , returnType );
735+ T data = handleResponse (request , response );
844736 return new ApiResponse <T >(response .code (), response .headers ().toMultimap (), data );
845- }
737+ }
846738 catch (IOException e ) {
847739 throw new ApiException (e );
848740 }
849741 }
850742
851- /**
852- * {@link #executeAsync(Call, Type, ApiCallback)}
853- *
854- * @param <T> Type
855- * @param call An instance of the Call object
856- * @param callback ApiCallback<T>
857- */
858- public <T > void executeAsync (Call call , ApiCallback <T > callback ) {
859- executeAsync (call , null , callback );
860- }
861-
862743 /**
863744 * Execute HTTP call asynchronously.
864745 *
865- * @see #execute(Call, Type)
866746 * @param <T> Type
747+ * @param request Request
867748 * @param call The callback to be executed when the API call finishes
868- * @param returnType Return type
869749 * @param callback ApiCallback
870750 */
871751 @ SuppressWarnings ("unchecked" )
872- public <T > void executeAsync (Call call , final Type returnType , final ApiCallback <T > callback ) {
752+ public <T > void executeAsync (Call call , RequestIfc request , final ApiCallback <T > callback ) {
873753 call .enqueue (new Callback () {
874754 @ Override
875755 public void onFailure (Request request , IOException e ) {
@@ -880,7 +760,7 @@ public void onFailure(Request request, IOException e) {
880760 public void onResponse (Response response ) throws IOException {
881761 T result ;
882762 try {
883- result = (T ) handleResponse (response , returnType );
763+ result = (T ) handleResponse (request , response );
884764 }
885765 catch (ApiException e ) {
886766 callback .onFailure (e , response .code (), response .headers ().toMultimap ());
@@ -895,29 +775,19 @@ public void onResponse(Response response) throws IOException {
895775 * Handle the given response, return the deserialized object when the response is successful.
896776 *
897777 * @param <T> Type
778+ * @param request Request
898779 * @param response Response
899- * @param returnType Return type
900780 * @throws ApiException If the response has a unsuccessful status code or
901781 * fail to deserialize the response body
902782 * @return Type
903783 */
904- public <T > T handleResponse (Response response , Type returnType ) throws ApiException {
784+ public <T > T handleResponse (RequestIfc request , Response response ) throws ApiException {
905785 if (response .isSuccessful ()) {
906- if (returnType == null || response .code () == 204 ) {
907- // returning null if the returnType is not defined,
908- // or the status code is 204 (No Content)
909- if (response .body () != null ) {
910- try {
911- response .body ().close ();
912- }
913- catch (IOException e ) {
914- throw new ApiException (response .message (), e , response .code (), response .headers ().toMultimap ());
915- }
916- }
917- return null ;
918- }
919- else {
920- return deserialize (response , returnType );
786+ try {
787+ return (T ) request .deserializeResponse (this , response );
788+ }
789+ catch (Exception e ) {
790+ throw new ApiException (e );
921791 }
922792 }
923793 else {
@@ -1269,7 +1139,7 @@ public Object parseModel(BodyPart bodyPart, Type returnType) throws IOException,
12691139 }
12701140
12711141 /**
1272- * Parse document from online response.
1142+ * Parse document from response.
12731143 */
12741144 public byte [] parseDocument (BodyPart bodyPart ) throws IOException , MessagingException {
12751145 InputStream is = bodyPart .getInputStream ();
@@ -1285,13 +1155,40 @@ public byte[] parseDocument(BodyPart bodyPart) throws IOException, MessagingExce
12851155 return buffer .toByteArray ();
12861156 }
12871157
1158+ /**
1159+ * Parse files collection from response.
1160+ */
1161+ public Map <String , byte []> parseFilesCollection (BodyPart part ) throws IOException , MessagingException {
1162+ return parseFilesCollection (part .getFileName (), part .getContentType (), bodyPartToArray (part ).toByteArray ());
1163+ }
1164+
1165+ /**
1166+ * Parse files collection from response.
1167+ */
1168+ public Map <String , byte []> parseFilesCollection (String filename , String dataType , byte [] data ) throws IOException , MessagingException {
1169+ Map <String , byte []> result = new HashMap <>();
1170+ if (dataType .startsWith ("multipart/mixed" )) {
1171+ ByteArrayDataSource dataSource = new ByteArrayDataSource (data , "multipart/mixed" );
1172+ MimeMultipart multipart = new MimeMultipart (dataSource );
1173+ for (int i = 0 ; i < multipart .getCount (); i ++) {
1174+ BodyPart part = multipart .getBodyPart (i );
1175+ result .put (part .getFileName (), bodyPartToArray (part ).toByteArray ());
1176+ }
1177+ }
1178+ else {
1179+ result .put (filename , data );
1180+ }
1181+
1182+ return result ;
1183+ }
1184+
12881185 /**
12891186 * Get multipart from response.
12901187 */
12911188 public MimeMultipart getMultipartFromResponse (Response response ) throws ApiException {
12921189 try {
12931190 InputStream in = response .body ().byteStream ();
1294- ByteArrayDataSource dataSource = new ByteArrayDataSource (in , "multipart/form-data " );
1191+ ByteArrayDataSource dataSource = new ByteArrayDataSource (in , "multipart/mixed " );
12951192 return new MimeMultipart (dataSource );
12961193 }
12971194 catch (IOException | MessagingException e ) {
@@ -1300,9 +1197,9 @@ public MimeMultipart getMultipartFromResponse(Response response) throws ApiExcep
13001197 }
13011198
13021199 /**
1303- * Parse batch part
1200+ * Convert body part to byte array
13041201 */
1305- public Object parseBatchPart ( Request masterRequest , BodyPart bodyPart , Type returnType ) throws IOException , MessagingException , ApiException {
1202+ public ByteArrayOutputStream bodyPartToArray ( BodyPart bodyPart ) throws MessagingException , IOException {
13061203 InputStream is = bodyPart .getInputStream ();
13071204 ByteArrayOutputStream buffer = new ByteArrayOutputStream ();
13081205
@@ -1313,7 +1210,15 @@ public Object parseBatchPart(Request masterRequest, BodyPart bodyPart, Type retu
13131210 buffer .write (data , 0 , nRead );
13141211 }
13151212
1213+ return buffer ;
1214+ }
1215+
1216+ /**
1217+ * Parse batch part
1218+ */
1219+ public Object parseBatchPart (RequestIfc apiRequest , Request sysRequest , BodyPart bodyPart ) throws IOException , MessagingException , ApiException {
13161220 try {
1221+ ByteArrayOutputStream buffer = bodyPartToArray (bodyPart );
13171222 String stringData = buffer .toString ("UTF-8" );
13181223 int lastSplitIndex = stringData .indexOf ("\r \n " );
13191224 Integer responseCode = Integer .parseInt (stringData .substring (0 , lastSplitIndex ).split ("\\ s+" )[0 ]);
@@ -1343,15 +1248,37 @@ public Object parseBatchPart(Request masterRequest, BodyPart bodyPart, Type retu
13431248 responseBody = ResponseBody .create (MediaType .parse (headers .get ("Content-Type" )), responseBytes );
13441249 }
13451250
1346- Response response = new Response .Builder ().request (masterRequest ).protocol (Protocol .HTTP_1_1 ).code (responseCode ).headers (headers ).body (responseBody ).build ();
1347- return deserialize ( response , returnType );
1251+ Response response = new Response .Builder ().request (sysRequest ).protocol (Protocol .HTTP_1_1 ).code (responseCode ).headers (headers ).body (responseBody ).build ();
1252+ return apiRequest . deserializeResponse ( this , response );
13481253 }
13491254 catch (Exception e ) {
13501255 throw new ApiException (400 , "Invalid response format." );
13511256 }
13521257 }
13531258
1354- /**
1259+ /**
1260+ * Find part in multipart by name
1261+ */
1262+ public BodyPart findBodyPartInMultipart (String name , MimeMultipart multipart ) throws MessagingException {
1263+ for (int i = 0 ; i < multipart .getCount (); i ++) {
1264+ BodyPart part = multipart .getBodyPart (i );
1265+ String [] header = part .getHeader ("Content-Disposition" );
1266+ header = String .join (";" , header ).split (";" );
1267+ for (int q = 0 ; q < header .length ; q ++) {
1268+ String headerPart = header [q ].trim ();
1269+ if (headerPart .startsWith ("name" )) {
1270+ String partName = headerPart .split ("=" )[1 ].trim ().replaceAll ("\" " , "" );
1271+ if (name .equals (partName )) {
1272+ return part ;
1273+ }
1274+ }
1275+ }
1276+ }
1277+
1278+ return null ;
1279+ }
1280+
1281+ /**
13551282 * Add OAuth2 header
13561283 *
13571284 * @param headerParams Map of request headers
0 commit comments