1616import org .apache .hc .client5 .http .impl .cache .CacheConfig ;
1717import org .apache .hc .client5 .http .impl .cache .CachingHttpClients ;
1818import org .apache .hc .client5 .http .impl .classic .CloseableHttpClient ;
19- import org .apache .hc .client5 .http .impl .classic .CloseableHttpResponse ;
2019import org .apache .hc .client5 .http .impl .classic .HttpClients ;
2120import org .apache .hc .client5 .http .impl .io .PoolingHttpClientConnectionManager ;
2221import org .apache .hc .client5 .http .io .HttpClientConnectionManager ;
2322import org .apache .hc .core5 .http .*;
2423import org .apache .hc .core5 .http .io .entity .EntityUtils ;
24+ import org .apache .hc .core5 .http .io .HttpClientResponseHandler ;
2525import org .apache .hc .core5 .util .Timeout ;
2626import se .michaelthelin .spotify .exceptions .SpotifyWebApiException ;
2727import se .michaelthelin .spotify .exceptions .detailed .*;
@@ -217,7 +217,7 @@ public String get(URI uri, Header[] headers) throws
217217 Level .FINE ,
218218 "GET request uses these headers: " + GSON .toJson (headers ));
219219
220- String responseBody = getResponseBody ( execute (httpClientCaching , httpGet ) );
220+ String responseBody = execute (httpClientCaching , httpGet );
221221
222222 httpGet .reset ();
223223
@@ -240,7 +240,7 @@ public String post(URI uri, Header[] headers, HttpEntity body) throws
240240 Level .FINE ,
241241 "POST request uses these headers: " + GSON .toJson (headers ));
242242
243- String responseBody = getResponseBody ( execute (httpClient , httpPost ) );
243+ String responseBody = execute (httpClient , httpPost );
244244
245245 httpPost .reset ();
246246
@@ -263,7 +263,7 @@ public String put(URI uri, Header[] headers, HttpEntity body) throws
263263 Level .FINE ,
264264 "PUT request uses these headers: " + GSON .toJson (headers ));
265265
266- String responseBody = getResponseBody ( execute (httpClient , httpPut ) );
266+ String responseBody = execute (httpClient , httpPut );
267267
268268 httpPut .reset ();
269269
@@ -286,17 +286,29 @@ public String delete(URI uri, Header[] headers, HttpEntity body) throws
286286 Level .FINE ,
287287 "DELETE request uses these headers: " + GSON .toJson (headers ));
288288
289- String responseBody = getResponseBody ( execute (httpClient , httpDelete ) );
289+ String responseBody = execute (httpClient , httpDelete );
290290
291291 httpDelete .reset ();
292292
293293 return responseBody ;
294294 }
295295
296- private CloseableHttpResponse execute (CloseableHttpClient httpClient , ClassicHttpRequest method ) throws
297- IOException {
296+ private String execute (CloseableHttpClient httpClient , ClassicHttpRequest method ) throws
297+ IOException , SpotifyWebApiException {
298298 HttpCacheContext context = HttpCacheContext .create ();
299- CloseableHttpResponse response = httpClient .execute (method , context );
299+ ResponseHandler responseHandler = new ResponseHandler ();
300+ String response ;
301+
302+ // TODO: in next major release don't extract cause below, throw http client's new ClientProtocolException
303+ try {
304+ response = httpClient .execute (method , context , responseHandler );
305+ } catch (IOException e ) {
306+ if (e .getCause () instanceof SpotifyWebApiException ) {
307+ throw (SpotifyWebApiException ) e .getCause ();
308+ }
309+
310+ throw e ;
311+ }
300312
301313 try {
302314 CacheResponseStatus responseStatus = context .getCacheResponseStatus ();
@@ -337,75 +349,77 @@ private CloseableHttpResponse execute(CloseableHttpClient httpClient, ClassicHtt
337349 return response ;
338350 }
339351
340- private String getResponseBody (CloseableHttpResponse httpResponse ) throws
341- IOException ,
342- SpotifyWebApiException ,
343- ParseException {
344-
345- final String responseBody = httpResponse .getEntity () != null
346- ? EntityUtils .toString (httpResponse .getEntity (), "UTF-8" )
347- : null ;
348- String errorMessage = httpResponse .getReasonPhrase ();
349-
350- SpotifyApi .LOGGER .log (
351- Level .FINE ,
352- "The http response has body " + responseBody );
353-
354- if (responseBody != null && !responseBody .isEmpty ()) {
355- try {
356- final JsonElement jsonElement = JsonParser .parseString (responseBody );
352+ static class ResponseHandler implements HttpClientResponseHandler <String > {
353+ @ Override
354+ public String handleResponse (ClassicHttpResponse httpResponse ) throws
355+ IOException ,
356+ SpotifyWebApiException ,
357+ ParseException {
358+ final String responseBody = httpResponse .getEntity () != null
359+ ? EntityUtils .toString (httpResponse .getEntity (), "UTF-8" )
360+ : null ;
361+ String errorMessage = httpResponse .getReasonPhrase ();
357362
358- if (jsonElement .isJsonObject ()) {
359- final JsonObject jsonObject = JsonParser .parseString (responseBody ).getAsJsonObject ();
360-
361- if (jsonObject .has ("error" )) {
362- if (jsonObject .has ("error_description" )) {
363- errorMessage = jsonObject .get ("error_description" ).getAsString ();
364- } else if (jsonObject .get ("error" ).isJsonObject () && jsonObject .getAsJsonObject ("error" ).has ("message" )) {
365- errorMessage = jsonObject .getAsJsonObject ("error" ).get ("message" ).getAsString ();
363+ SpotifyApi .LOGGER .log (
364+ Level .FINE ,
365+ "The http response has body " + responseBody );
366+
367+ if (responseBody != null && !responseBody .isEmpty ()) {
368+ try {
369+ final JsonElement jsonElement = JsonParser .parseString (responseBody );
370+
371+ if (jsonElement .isJsonObject ()) {
372+ final JsonObject jsonObject = JsonParser .parseString (responseBody ).getAsJsonObject ();
373+
374+ if (jsonObject .has ("error" )) {
375+ if (jsonObject .has ("error_description" )) {
376+ errorMessage = jsonObject .get ("error_description" ).getAsString ();
377+ } else if (jsonObject .get ("error" ).isJsonObject () && jsonObject .getAsJsonObject ("error" ).has ("message" )) {
378+ errorMessage = jsonObject .getAsJsonObject ("error" ).get ("message" ).getAsString ();
379+ }
366380 }
367381 }
382+ } catch (JsonSyntaxException e ) {
383+ // Not necessary
368384 }
369- } catch (JsonSyntaxException e ) {
370- // Not necessary
371385 }
372- }
373386
374- SpotifyApi .LOGGER .log (
375- Level .FINE ,
376- "The http response has status code " + httpResponse .getCode ());
377-
378- switch (httpResponse .getCode ()) {
379- case HttpStatus .SC_BAD_REQUEST :
380- throw new BadRequestException (errorMessage );
381- case HttpStatus .SC_UNAUTHORIZED :
382- throw new UnauthorizedException (errorMessage );
383- case HttpStatus .SC_FORBIDDEN :
384- throw new ForbiddenException (errorMessage );
385- case HttpStatus .SC_NOT_FOUND :
386- throw new NotFoundException (errorMessage );
387- case 429 : // TOO_MANY_REQUESTS (additional status code, RFC 6585)
388- // Sets "Retry-After" header as described at https://beta.developer.spotify.com/documentation/web-api/#rate-limiting
389- Header header = httpResponse .getFirstHeader ("Retry-After" );
390-
391- if (header != null ) {
392- throw new TooManyRequestsException (errorMessage , Integer .parseInt (header .getValue ()));
393- } else {
394- throw new TooManyRequestsException (errorMessage );
395- }
396- case HttpStatus .SC_INTERNAL_SERVER_ERROR :
397- throw new InternalServerErrorException (errorMessage );
398- case HttpStatus .SC_BAD_GATEWAY :
399- throw new BadGatewayException (errorMessage );
400- case HttpStatus .SC_SERVICE_UNAVAILABLE :
401- throw new ServiceUnavailableException (errorMessage );
402- default :
403- if (httpResponse .getCode () >= 400 && httpResponse .getCode () < 500 ) {
387+ SpotifyApi .LOGGER .log (
388+ Level .FINE ,
389+ "The http response has status code " + httpResponse .getCode ());
390+
391+ switch (httpResponse .getCode ()) {
392+ case HttpStatus .SC_BAD_REQUEST :
404393 throw new BadRequestException (errorMessage );
405- } else if (httpResponse .getCode () >= 500 ) {
394+ case HttpStatus .SC_UNAUTHORIZED :
395+ throw new UnauthorizedException (errorMessage );
396+ case HttpStatus .SC_FORBIDDEN :
397+ throw new ForbiddenException (errorMessage );
398+ case HttpStatus .SC_NOT_FOUND :
399+ throw new NotFoundException (errorMessage );
400+ case 429 : // TOO_MANY_REQUESTS (additional status code, RFC 6585)
401+ // Sets "Retry-After" header as described at https://beta.developer.spotify.com/documentation/web-api/#rate-limiting
402+ Header header = httpResponse .getFirstHeader ("Retry-After" );
403+
404+ if (header != null ) {
405+ throw new TooManyRequestsException (errorMessage , Integer .parseInt (header .getValue ()));
406+ } else {
407+ throw new TooManyRequestsException (errorMessage );
408+ }
409+ case HttpStatus .SC_INTERNAL_SERVER_ERROR :
406410 throw new InternalServerErrorException (errorMessage );
407- }
408- return responseBody ;
411+ case HttpStatus .SC_BAD_GATEWAY :
412+ throw new BadGatewayException (errorMessage );
413+ case HttpStatus .SC_SERVICE_UNAVAILABLE :
414+ throw new ServiceUnavailableException (errorMessage );
415+ default :
416+ if (httpResponse .getCode () >= 400 && httpResponse .getCode () < 500 ) {
417+ throw new BadRequestException (errorMessage );
418+ } else if (httpResponse .getCode () >= 500 ) {
419+ throw new InternalServerErrorException (errorMessage );
420+ }
421+ return responseBody ;
422+ }
409423 }
410424 }
411425
0 commit comments