|
13 | 13 | import java.text.SimpleDateFormat; |
14 | 14 | import java.util.Date; |
15 | 15 | import java.util.UUID; |
| 16 | +import java.util.Arrays; |
| 17 | +import java.lang.reflect.Field; |
16 | 18 |
|
17 | 19 | public class PartnerAPI { |
18 | 20 | private Config config; |
19 | 21 | private HttpClient httpClient; |
20 | 22 | private Crypto crypto; |
21 | 23 | private GsonBuilder gsonBuilder; |
22 | 24 | private Gson gson; |
| 25 | + private static final int MAX_RETRIES = 2; |
23 | 26 |
|
24 | 27 | public PartnerAPI(File configFile) throws ProcessingError, ConfigFileNotFoundException, |
25 | 28 | P12FileNotFoundException, SSLInitializeError { |
@@ -62,24 +65,59 @@ public Pong ping() throws ProcessingError, ConnectionError { |
62 | 65 | return gson.fromJson(response.getBody(), Pong.class); |
63 | 66 | } |
64 | 67 |
|
65 | | - public String encodeRequest(Request request) throws ProcessingError { |
66 | | - String requestData = gson.toJson(request); |
67 | | - return constructContent(request.method().toString(), requestData); |
| 68 | + private boolean isRetriable(Request request) { |
| 69 | + String[] retriableMethods = {"GET", "PATCH"}; |
| 70 | + if (Arrays.asList(retriableMethods).contains(request.method().toString())) { |
| 71 | + return true; |
| 72 | + } |
| 73 | + try { |
| 74 | + Field field = request.getClass().getDeclaredField("requestId"); |
| 75 | + field.setAccessible(true); |
| 76 | + boolean hasRequestId = field.get(request) != null; |
| 77 | + field.setAccessible(false); |
| 78 | + return hasRequestId; |
| 79 | + } catch (NoSuchFieldException ex) { |
| 80 | + } catch (IllegalAccessException ex) { } |
| 81 | + return false; |
68 | 82 | } |
69 | 83 |
|
70 | 84 | public Response send(Request request) throws ProcessingError, ConnectionError, PartnerRequestError { |
71 | | - HttpClient.Response response = httpClient.post(request.path(), encodeRequest(request), config.acceptLanguage); |
72 | | - JsonResponse json = gson.fromJson(response.getBody(), JsonResponse.class); |
73 | | - if (json.responseData == null) { |
74 | | - ErrorResponse errorResponse = gson.fromJson(response.getBody(), ErrorResponse.class); |
75 | | - throw new PartnerRequestError(errorResponse.type, errorResponse.message, response.getBody()); |
76 | | - } |
77 | | - String responseData = crypto.decode(json.responseData); |
78 | | - ErrorResponse errorResponse = gson.fromJson(responseData, ErrorResponse.class); |
79 | | - if (!errorResponse.isValid()) { |
80 | | - return gson.fromJson(responseData, request.getResponseClass()); |
81 | | - } else { |
82 | | - throw new PartnerRequestError(errorResponse.type, errorResponse.message, responseData); |
| 85 | + Integer retry = 0; |
| 86 | + boolean isRetriable = isRetriable(request); |
| 87 | + String requestData = gson.toJson(request); |
| 88 | + int statusCode = 0; |
| 89 | + while (true) { |
| 90 | + try { |
| 91 | + HttpClient.Response response = httpClient.post(request.path(), constructContent(request.method().toString(), requestData), config.acceptLanguage); |
| 92 | + statusCode = response.getStatus(); |
| 93 | + JsonResponse json = gson.fromJson(response.getBody(), JsonResponse.class); |
| 94 | + if (json.responseData == null) { |
| 95 | + ErrorResponse errorResponse = gson.fromJson(response.getBody(), ErrorResponse.class); |
| 96 | + throw new PartnerRequestError(errorResponse.type, errorResponse.message, response.getBody()); |
| 97 | + } |
| 98 | + String responseData = crypto.decode(json.responseData); |
| 99 | + ErrorResponse errorResponse = gson.fromJson(responseData, ErrorResponse.class); |
| 100 | + if (!errorResponse.isValid()) { |
| 101 | + return gson.fromJson(responseData, request.getResponseClass()); |
| 102 | + } else { |
| 103 | + throw new PartnerRequestError(errorResponse.type, errorResponse.message, responseData); |
| 104 | + } |
| 105 | + } catch (ConnectionError ex) { |
| 106 | + if (this.MAX_RETRIES <= retry || !isRetriable) { |
| 107 | + throw ex; |
| 108 | + } |
| 109 | + } catch (PartnerRequestError ex) { |
| 110 | + if (ex.getType().equals("request_id_conflict")) { |
| 111 | + throw new RequestIdConflict(ex.getType(), ex.getMessage(), ex.getRawJson()); |
| 112 | + } |
| 113 | + if (!isRetriable) { |
| 114 | + throw ex; |
| 115 | + } |
| 116 | + if (!(statusCode == 503 && retry < this.MAX_RETRIES)) { |
| 117 | + throw ex; |
| 118 | + } |
| 119 | + } |
| 120 | + ++retry; |
83 | 121 | } |
84 | 122 | } |
85 | 123 |
|
|
0 commit comments