embulk-input-marketo_extended 0.6.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.github/PULL_REQUEST_TEMPLATE.md +37 -0
  3. data/.gitignore +14 -0
  4. data/.travis.yml +6 -0
  5. data/CHANGELOG.md +170 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +213 -0
  8. data/build.gradle +103 -0
  9. data/config/checkstyle/checkstyle.xml +128 -0
  10. data/config/checkstyle/default.xml +108 -0
  11. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  12. data/gradle/wrapper/gradle-wrapper.properties +6 -0
  13. data/gradlew +169 -0
  14. data/gradlew.bat +84 -0
  15. data/lib/embulk/input/marketo.rb +3 -0
  16. data/settings.gradle +1 -0
  17. data/src/main/java/org/embulk/input/marketo/CsvTokenizer.java +700 -0
  18. data/src/main/java/org/embulk/input/marketo/MarketoInputPlugin.java +15 -0
  19. data/src/main/java/org/embulk/input/marketo/MarketoInputPluginDelegate.java +100 -0
  20. data/src/main/java/org/embulk/input/marketo/MarketoService.java +38 -0
  21. data/src/main/java/org/embulk/input/marketo/MarketoServiceImpl.java +245 -0
  22. data/src/main/java/org/embulk/input/marketo/MarketoUtils.java +212 -0
  23. data/src/main/java/org/embulk/input/marketo/delegate/ActivityBulkExtractInputPlugin.java +167 -0
  24. data/src/main/java/org/embulk/input/marketo/delegate/CampaignInputPlugin.java +48 -0
  25. data/src/main/java/org/embulk/input/marketo/delegate/CustomObjectInputPlugin.java +75 -0
  26. data/src/main/java/org/embulk/input/marketo/delegate/CustomObjectResponseMapperBuilder.java +81 -0
  27. data/src/main/java/org/embulk/input/marketo/delegate/LeadBulkExtractInputPlugin.java +66 -0
  28. data/src/main/java/org/embulk/input/marketo/delegate/LeadServiceResponseMapperBuilder.java +85 -0
  29. data/src/main/java/org/embulk/input/marketo/delegate/LeadWithListInputPlugin.java +64 -0
  30. data/src/main/java/org/embulk/input/marketo/delegate/LeadWithProgramInputPlugin.java +60 -0
  31. data/src/main/java/org/embulk/input/marketo/delegate/MarketoBaseBulkExtractInputPlugin.java +441 -0
  32. data/src/main/java/org/embulk/input/marketo/delegate/MarketoBaseInputPluginDelegate.java +92 -0
  33. data/src/main/java/org/embulk/input/marketo/delegate/ProgramInputPlugin.java +228 -0
  34. data/src/main/java/org/embulk/input/marketo/exception/MarketoAPIException.java +30 -0
  35. data/src/main/java/org/embulk/input/marketo/model/BulkExtractRangeHeader.java +26 -0
  36. data/src/main/java/org/embulk/input/marketo/model/MarketoAccessTokenResponse.java +92 -0
  37. data/src/main/java/org/embulk/input/marketo/model/MarketoBulkExtractRequest.java +68 -0
  38. data/src/main/java/org/embulk/input/marketo/model/MarketoError.java +40 -0
  39. data/src/main/java/org/embulk/input/marketo/model/MarketoField.java +126 -0
  40. data/src/main/java/org/embulk/input/marketo/model/MarketoResponse.java +82 -0
  41. data/src/main/java/org/embulk/input/marketo/model/filter/DateRangeFilter.java +40 -0
  42. data/src/main/java/org/embulk/input/marketo/rest/MarketoBaseRestClient.java +306 -0
  43. data/src/main/java/org/embulk/input/marketo/rest/MarketoInputStreamResponseEntityReader.java +69 -0
  44. data/src/main/java/org/embulk/input/marketo/rest/MarketoRESTEndpoint.java +47 -0
  45. data/src/main/java/org/embulk/input/marketo/rest/MarketoResponseJetty92EntityReader.java +89 -0
  46. data/src/main/java/org/embulk/input/marketo/rest/MarketoRestClient.java +569 -0
  47. data/src/main/java/org/embulk/input/marketo/rest/RecordPagingIterable.java +180 -0
  48. data/src/test/java/org/embulk/input/marketo/MarketoServiceImplTest.java +140 -0
  49. data/src/test/java/org/embulk/input/marketo/MarketoUtilsTest.java +87 -0
  50. data/src/test/java/org/embulk/input/marketo/delegate/ActivityBulkExtractInputPluginTest.java +128 -0
  51. data/src/test/java/org/embulk/input/marketo/delegate/CampaignInputPluginTest.java +73 -0
  52. data/src/test/java/org/embulk/input/marketo/delegate/CustomObjectInputPluginTest.java +102 -0
  53. data/src/test/java/org/embulk/input/marketo/delegate/LeadBulkExtractInputPluginTest.java +99 -0
  54. data/src/test/java/org/embulk/input/marketo/delegate/LeadServiceResponseMapperBuilderTest.java +119 -0
  55. data/src/test/java/org/embulk/input/marketo/delegate/LeadWithListInputPluginTest.java +101 -0
  56. data/src/test/java/org/embulk/input/marketo/delegate/LeadWithProgramInputPluginTest.java +103 -0
  57. data/src/test/java/org/embulk/input/marketo/delegate/MarketoBaseBulkExtractInputPluginTest.java +169 -0
  58. data/src/test/java/org/embulk/input/marketo/delegate/ProgramInputPluginTest.java +343 -0
  59. data/src/test/java/org/embulk/input/marketo/rest/MarketoBaseRestClientTest.java +368 -0
  60. data/src/test/java/org/embulk/input/marketo/rest/MarketoRestClientTest.java +584 -0
  61. data/src/test/resources/config/activity_bulk_extract_config.yaml +7 -0
  62. data/src/test/resources/config/custom_object_config.yaml +8 -0
  63. data/src/test/resources/config/lead_bulk_extract_config.yaml +8 -0
  64. data/src/test/resources/config/rest_config.yaml +3 -0
  65. data/src/test/resources/fixtures/activity_extract1.csv +35 -0
  66. data/src/test/resources/fixtures/activity_extract2.csv +22 -0
  67. data/src/test/resources/fixtures/activity_types.json +22 -0
  68. data/src/test/resources/fixtures/all_program_full.json +53 -0
  69. data/src/test/resources/fixtures/campaign_response.json +38 -0
  70. data/src/test/resources/fixtures/campaign_response_full.json +102 -0
  71. data/src/test/resources/fixtures/custom_object_describe.json +124 -0
  72. data/src/test/resources/fixtures/custom_object_describe_marketo_fields_full.json +22 -0
  73. data/src/test/resources/fixtures/custom_object_expected.json +66 -0
  74. data/src/test/resources/fixtures/custom_object_response.json +24 -0
  75. data/src/test/resources/fixtures/custom_object_response_full.json +23 -0
  76. data/src/test/resources/fixtures/lead_by_list.json +33 -0
  77. data/src/test/resources/fixtures/lead_by_program_response.json +47 -0
  78. data/src/test/resources/fixtures/lead_describe.json +221 -0
  79. data/src/test/resources/fixtures/lead_describe_expected.json +66 -0
  80. data/src/test/resources/fixtures/lead_describe_marketo_fields_full.json +518 -0
  81. data/src/test/resources/fixtures/lead_extract1.csv +11 -0
  82. data/src/test/resources/fixtures/lead_response_full.json +2402 -0
  83. data/src/test/resources/fixtures/lead_with_program_full.json +17 -0
  84. data/src/test/resources/fixtures/leads_extract2.csv +10 -0
  85. data/src/test/resources/fixtures/list_reponse_full.json +191 -0
  86. data/src/test/resources/fixtures/lists_response.json +31 -0
  87. data/src/test/resources/fixtures/program_response.json +71 -0
  88. metadata +171 -0
@@ -0,0 +1,68 @@
1
+ package org.embulk.input.marketo.model;
2
+
3
+ import java.util.HashMap;
4
+ import java.util.List;
5
+ import java.util.Map;
6
+
7
+ /**
8
+ * Created by tai.khuu on 8/27/17.
9
+ */
10
+ public class MarketoBulkExtractRequest
11
+ {
12
+ private List<String> fields;
13
+ private String format;
14
+
15
+ private Map<String, String> columnHeaderNames;
16
+
17
+ private Map<String, Object> filter = new HashMap<>();
18
+
19
+ public List<String> getFields()
20
+ {
21
+ return fields;
22
+ }
23
+
24
+ public void setFields(List<String> fields)
25
+ {
26
+ this.fields = fields;
27
+ }
28
+
29
+ public String getFormat()
30
+ {
31
+ return format;
32
+ }
33
+
34
+ public void setFormat(String format)
35
+ {
36
+ this.format = format;
37
+ }
38
+
39
+ public Map<String, String> getColumnHeaderNames()
40
+ {
41
+ return columnHeaderNames;
42
+ }
43
+
44
+ public void setColumnHeaderNames(Map<String, String> columnHeaderNames)
45
+ {
46
+ this.columnHeaderNames = columnHeaderNames;
47
+ }
48
+
49
+ public Map<String, Object> getFilter()
50
+ {
51
+ return filter;
52
+ }
53
+
54
+ public void setFilter(Map<String, Object> filter)
55
+ {
56
+ this.filter = filter;
57
+ }
58
+
59
+ @Override
60
+ public String toString()
61
+ {
62
+ return "MarketoBulkExtractRequest{" +
63
+ "format='" + format + '\'' +
64
+ ", columnHeaderNames=" + columnHeaderNames +
65
+ ", filter=" + filter +
66
+ '}';
67
+ }
68
+ }
@@ -0,0 +1,40 @@
1
+ package org.embulk.input.marketo.model;
2
+
3
+ /**
4
+ * Created by tai.khuu on 8/25/17.
5
+ */
6
+ public class MarketoError
7
+ {
8
+ private String code;
9
+
10
+ private String message;
11
+
12
+ public String getCode()
13
+ {
14
+ return code;
15
+ }
16
+
17
+ public void setCode(String code)
18
+ {
19
+ this.code = code;
20
+ }
21
+
22
+ public String getMessage()
23
+ {
24
+ return message;
25
+ }
26
+
27
+ public void setMessage(String message)
28
+ {
29
+ this.message = message;
30
+ }
31
+
32
+ @Override
33
+ public String toString()
34
+ {
35
+ return "MarketoError{" +
36
+ "code='" + code + '\'' +
37
+ ", message='" + message + '\'' +
38
+ '}';
39
+ }
40
+ }
@@ -0,0 +1,126 @@
1
+ package org.embulk.input.marketo.model;
2
+
3
+ import com.google.common.base.Optional;
4
+ import org.embulk.input.marketo.MarketoUtils;
5
+ import org.embulk.spi.type.Type;
6
+ import org.embulk.spi.type.Types;
7
+
8
+ /**
9
+ * Created by tai.khuu on 9/22/17.
10
+ */
11
+
12
+ public class MarketoField
13
+ {
14
+ private String name;
15
+
16
+ private MarketoDataType marketoDataType;
17
+
18
+ public MarketoField(){}
19
+
20
+ public MarketoField(String name, String dataType)
21
+ {
22
+ this.name = name;
23
+ try {
24
+ marketoDataType = MarketoDataType.valueOf(dataType.toUpperCase());
25
+ }
26
+ catch (IllegalArgumentException ex) {
27
+ marketoDataType = MarketoDataType.STRING;
28
+ }
29
+ }
30
+
31
+ public MarketoField(String name, MarketoDataType marketoDataType)
32
+ {
33
+ this.name = name;
34
+ this.marketoDataType = marketoDataType;
35
+ }
36
+
37
+ public String getName()
38
+ {
39
+ return name;
40
+ }
41
+
42
+ public MarketoDataType getMarketoDataType()
43
+ {
44
+ return marketoDataType;
45
+ }
46
+
47
+ @Override
48
+ public boolean equals(Object o)
49
+ {
50
+ if (this == o) {
51
+ return true;
52
+ }
53
+ if (o == null || getClass() != o.getClass()) {
54
+ return false;
55
+ }
56
+
57
+ MarketoField field = (MarketoField) o;
58
+
59
+ if (name != null ? !name.equals(field.name) : field.name != null) {
60
+ return false;
61
+ }
62
+ return marketoDataType == field.marketoDataType;
63
+ }
64
+
65
+ @Override
66
+ public int hashCode()
67
+ {
68
+ int result = name != null ? name.hashCode() : 0;
69
+ result = 31 * result + (marketoDataType != null ? marketoDataType.hashCode() : 0);
70
+ return result;
71
+ }
72
+
73
+ public enum MarketoDataType
74
+ {
75
+ DATETIME(Types.TIMESTAMP, MarketoUtils.MARKETO_DATE_TIME_FORMAT),
76
+ EMAIL(Types.STRING),
77
+ FLOAT(Types.DOUBLE),
78
+ INTEGER(Types.LONG),
79
+ FORMULA(Types.STRING),
80
+ PERCENT(Types.DOUBLE),
81
+ URL(Types.STRING),
82
+ PHONE(Types.STRING),
83
+ TEXTAREA(Types.STRING),
84
+ TEXT(Types.STRING),
85
+ STRING(Types.STRING),
86
+ SCORE(Types.LONG),
87
+ BOOLEAN(Types.BOOLEAN),
88
+ CURRENCY(Types.DOUBLE),
89
+ DATE(Types.TIMESTAMP, MarketoUtils.MARKETO_DATE_FORMAT),
90
+ REFERENCE(Types.STRING);
91
+
92
+ private Type type;
93
+
94
+ private String format;
95
+
96
+ MarketoDataType(Type type, String format)
97
+ {
98
+ this.type = type;
99
+ this.format = format;
100
+ }
101
+
102
+ MarketoDataType(Type type)
103
+ {
104
+ this.type = type;
105
+ }
106
+
107
+ public Type getType()
108
+ {
109
+ return type;
110
+ }
111
+
112
+ public Optional<String> getFormat()
113
+ {
114
+ return Optional.fromNullable(format);
115
+ }
116
+ }
117
+
118
+ @Override
119
+ public String toString()
120
+ {
121
+ return "MarketoField{" +
122
+ "name='" + name + '\'' +
123
+ ", marketoDataType=" + marketoDataType +
124
+ '}';
125
+ }
126
+ }
@@ -0,0 +1,82 @@
1
+ package org.embulk.input.marketo.model;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.List;
5
+
6
+ /**
7
+ * Created by tai.khuu on 8/25/17.
8
+ */
9
+ public class MarketoResponse<T>
10
+ {
11
+ private String requestId;
12
+
13
+ private boolean success;
14
+
15
+ private String nextPageToken;
16
+
17
+ private boolean moreResult;
18
+
19
+ private List<MarketoError> errors;
20
+
21
+ private List<T> result = new ArrayList<>();
22
+
23
+ public String getRequestId()
24
+ {
25
+ return requestId;
26
+ }
27
+
28
+ public void setRequestId(String requestId)
29
+ {
30
+ this.requestId = requestId;
31
+ }
32
+
33
+ public boolean isSuccess()
34
+ {
35
+ return success;
36
+ }
37
+
38
+ public void setSuccess(boolean success)
39
+ {
40
+ this.success = success;
41
+ }
42
+
43
+ public List<MarketoError> getErrors()
44
+ {
45
+ return errors;
46
+ }
47
+
48
+ public void setErrors(List<MarketoError> errors)
49
+ {
50
+ this.errors = errors;
51
+ }
52
+
53
+ public List<T> getResult()
54
+ {
55
+ return result;
56
+ }
57
+
58
+ public void setResult(List<T> result)
59
+ {
60
+ this.result = result;
61
+ }
62
+
63
+ public String getNextPageToken()
64
+ {
65
+ return nextPageToken;
66
+ }
67
+
68
+ public void setNextPageToken(String nextPageToken)
69
+ {
70
+ this.nextPageToken = nextPageToken;
71
+ }
72
+
73
+ public boolean isMoreResult()
74
+ {
75
+ return moreResult;
76
+ }
77
+
78
+ public void setMoreResult(boolean moreResult)
79
+ {
80
+ this.moreResult = moreResult;
81
+ }
82
+ }
@@ -0,0 +1,40 @@
1
+ package org.embulk.input.marketo.model.filter;
2
+
3
+ /**
4
+ * Created by tai.khuu on 8/27/17.
5
+ */
6
+ public class DateRangeFilter
7
+ {
8
+ private String startAt;
9
+
10
+ private String endAt;
11
+
12
+ public String getStartAt()
13
+ {
14
+ return startAt;
15
+ }
16
+
17
+ public void setStartAt(String startAt)
18
+ {
19
+ this.startAt = startAt;
20
+ }
21
+
22
+ public String getEndAt()
23
+ {
24
+ return endAt;
25
+ }
26
+
27
+ public void setEndAt(String endAt)
28
+ {
29
+ this.endAt = endAt;
30
+ }
31
+
32
+ @Override
33
+ public String toString()
34
+ {
35
+ return "DateRangeFilter{" +
36
+ "startAt='" + startAt + '\'' +
37
+ ", endAt='" + endAt + '\'' +
38
+ '}';
39
+ }
40
+ }
@@ -0,0 +1,306 @@
1
+ package org.embulk.input.marketo.rest;
2
+
3
+ import com.fasterxml.jackson.databind.ObjectMapper;
4
+ import com.google.common.annotations.VisibleForTesting;
5
+ import com.google.common.base.Optional;
6
+ import com.google.common.collect.ArrayListMultimap;
7
+ import com.google.common.collect.Multimap;
8
+ import org.apache.commons.lang3.StringUtils;
9
+ import org.eclipse.jetty.client.HttpClient;
10
+ import org.eclipse.jetty.client.HttpResponseException;
11
+ import org.eclipse.jetty.client.api.ContentProvider;
12
+ import org.eclipse.jetty.client.api.Request;
13
+ import org.eclipse.jetty.client.api.Response;
14
+ import org.eclipse.jetty.client.util.StringContentProvider;
15
+ import org.eclipse.jetty.http.HttpMethod;
16
+ import org.embulk.config.ConfigException;
17
+ import org.embulk.input.marketo.exception.MarketoAPIException;
18
+ import org.embulk.input.marketo.model.MarketoAccessTokenResponse;
19
+ import org.embulk.input.marketo.model.MarketoError;
20
+ import org.embulk.spi.DataException;
21
+ import org.embulk.spi.Exec;
22
+ import org.embulk.util.retryhelper.jetty92.Jetty92ResponseReader;
23
+ import org.embulk.util.retryhelper.jetty92.Jetty92RetryHelper;
24
+ import org.embulk.util.retryhelper.jetty92.Jetty92SingleRequester;
25
+ import org.embulk.util.retryhelper.jetty92.StringJetty92ResponseEntityReader;
26
+ import org.slf4j.Logger;
27
+
28
+ import java.io.EOFException;
29
+ import java.io.IOException;
30
+ import java.net.SocketTimeoutException;
31
+ import java.nio.charset.StandardCharsets;
32
+ import java.util.Map;
33
+ import java.util.concurrent.ExecutionException;
34
+ import java.util.concurrent.TimeoutException;
35
+
36
+ import static com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS;
37
+ import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
38
+
39
+ /**
40
+ * Marketo base rest client
41
+ * Created by tai.khuu on 9/7/17.
42
+ */
43
+ public class MarketoBaseRestClient implements AutoCloseable
44
+ {
45
+ private static final Logger LOGGER = Exec.getLogger(MarketoBaseRestClient.class);
46
+
47
+ private static final String APPLICATION_JSON = "application/json";
48
+
49
+ private static final String AUTHORIZATION_HEADER = "Authorization";
50
+
51
+ private String identityEndPoint;
52
+
53
+ private String clientId;
54
+
55
+ private String clientSecret;
56
+
57
+ private String accessToken;
58
+
59
+ private int marketoLimitIntervalMillis;
60
+
61
+ private Jetty92RetryHelper retryHelper;
62
+
63
+ protected long readTimeoutMillis;
64
+
65
+ private Optional<String> partnerApiKey;
66
+
67
+ protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().configure(FAIL_ON_UNKNOWN_PROPERTIES, false).configure(ALLOW_UNQUOTED_CONTROL_CHARS, false);
68
+
69
+ MarketoBaseRestClient(String identityEndPoint,
70
+ String clientId,
71
+ String clientSecret,
72
+ Optional<String> partnerApiKey,
73
+ int marketoLimitIntervalMillis,
74
+ long readTimeoutMillis,
75
+ Jetty92RetryHelper retryHelper)
76
+ {
77
+ this.identityEndPoint = identityEndPoint;
78
+ this.clientId = clientId;
79
+ this.clientSecret = clientSecret;
80
+ this.readTimeoutMillis = readTimeoutMillis;
81
+ this.retryHelper = retryHelper;
82
+ this.marketoLimitIntervalMillis = marketoLimitIntervalMillis;
83
+ this.partnerApiKey = partnerApiKey;
84
+ }
85
+
86
+ private void renewAccessToken()
87
+ {
88
+ accessToken = getAccessTokenWithWrappedException();
89
+ }
90
+
91
+ @VisibleForTesting
92
+ public String getAccessToken()
93
+ {
94
+ if (accessToken == null) {
95
+ synchronized (this) {
96
+ if (accessToken == null) {
97
+ accessToken = getAccessTokenWithWrappedException();
98
+ }
99
+ }
100
+ }
101
+ return accessToken;
102
+ }
103
+
104
+ private String requestAccessToken()
105
+ {
106
+ final Multimap<String, String> params = ArrayListMultimap.create();
107
+ params.put("client_id", clientId);
108
+ params.put("client_secret", clientSecret);
109
+ params.put("grant_type", "client_credentials");
110
+
111
+ // add partner api key to the request
112
+ if (partnerApiKey.isPresent()) {
113
+ LOGGER.info("> Request access_token with partner_id: {}", StringUtils.abbreviate(partnerApiKey.get(), 8));
114
+ params.put("partner_id", partnerApiKey.get());
115
+ }
116
+
117
+ String response = retryHelper.requestWithRetry(new StringJetty92ResponseEntityReader(readTimeoutMillis), new Jetty92SingleRequester()
118
+ {
119
+ @Override
120
+ public void requestOnce(HttpClient client, Response.Listener responseListener)
121
+ {
122
+ Request request = client.newRequest(identityEndPoint + MarketoRESTEndpoint.ACCESS_TOKEN.getEndpoint()).method(HttpMethod.GET);
123
+ for (String key : params.keySet()) {
124
+ for (String value : params.get(key)) {
125
+ request.param(key, value);
126
+ }
127
+ }
128
+ request.send(responseListener);
129
+ }
130
+
131
+ @Override
132
+ protected boolean isResponseStatusToRetry(Response response)
133
+ {
134
+ return response.getStatus() == 502;
135
+ }
136
+
137
+ @Override
138
+ protected boolean isExceptionToRetry(Exception exception)
139
+ {
140
+ if (exception instanceof TimeoutException || exception instanceof SocketTimeoutException || exception instanceof EOFException || super.isExceptionToRetry(exception)) {
141
+ return true;
142
+ }
143
+ // unwrap
144
+ if (exception instanceof ExecutionException || (exception instanceof IOException && exception.getCause() != null)) {
145
+ return this.toRetry((Exception) exception.getCause());
146
+ }
147
+ return false;
148
+ }
149
+ });
150
+
151
+ MarketoAccessTokenResponse accessTokenResponse;
152
+
153
+ try {
154
+ accessTokenResponse = OBJECT_MAPPER.readValue(response, MarketoAccessTokenResponse.class);
155
+ }
156
+ catch (IOException e) {
157
+ LOGGER.error("Exception when parse access token response", e);
158
+ throw new DataException("Can't parse access token response");
159
+ }
160
+ if (accessTokenResponse.hasError()) {
161
+ throw new DataException(accessTokenResponse.getErrorDescription());
162
+ }
163
+ LOGGER.info("Acquired new access token");
164
+ return accessTokenResponse.getAccessToken();
165
+ }
166
+
167
+ protected <T> T doGet(final String target, final Map<String, String> headers, final Multimap<String, String> params, Jetty92ResponseReader<T> responseReader)
168
+ {
169
+ return doRequestWithWrappedException(target, HttpMethod.GET, headers, params, null, responseReader);
170
+ }
171
+
172
+ protected <T> T doPost(final String target, final Map<String, String> headers, final Multimap<String, String> params, final String content, Jetty92ResponseReader<T> responseReader)
173
+ {
174
+ StringContentProvider contentProvider = null;
175
+ if (content != null) {
176
+ contentProvider = new StringContentProvider(APPLICATION_JSON, content, StandardCharsets.UTF_8);
177
+ }
178
+ return doPost(target, headers, params, responseReader, contentProvider);
179
+ }
180
+
181
+ protected <T> T doPost(final String target, final Map<String, String> headers, final Multimap<String, String> params, Jetty92ResponseReader<T> responseReader, final ContentProvider content)
182
+ {
183
+ return doRequestWithWrappedException(target, HttpMethod.POST, headers, params, content, responseReader);
184
+ }
185
+
186
+ private String getAccessTokenWithWrappedException()
187
+ {
188
+ try {
189
+ return requestAccessToken();
190
+ }
191
+ catch (Exception e) {
192
+ if (e instanceof HttpResponseException) {
193
+ throw new ConfigException(e.getMessage());
194
+ }
195
+ if (e.getCause() instanceof HttpResponseException) {
196
+ throw new ConfigException(e.getCause().getMessage());
197
+ }
198
+ throw e;
199
+ }
200
+ }
201
+
202
+ private <T> T doRequestWithWrappedException(final String target, final HttpMethod method, final Map<String, String> headers, final Multimap<String, String> params, final ContentProvider contentProvider, Jetty92ResponseReader<T> responseReader)
203
+ {
204
+ try {
205
+ return doRequest(target, method, headers, params, contentProvider, responseReader);
206
+ }
207
+ catch (Exception e) {
208
+ if (e instanceof MarketoAPIException || e instanceof HttpResponseException) {
209
+ throw new DataException(e.getMessage());
210
+ }
211
+ if (e.getCause() instanceof MarketoAPIException || e.getCause() instanceof HttpResponseException) {
212
+ throw new DataException(e.getCause().getMessage());
213
+ }
214
+ throw e;
215
+ }
216
+ }
217
+
218
+ protected <T> T doRequest(final String target, final HttpMethod method, final Map<String, String> headers, final Multimap<String, String> params, final ContentProvider contentProvider, Jetty92ResponseReader<T> responseReader)
219
+ {
220
+ return retryHelper.requestWithRetry(responseReader, new Jetty92SingleRequester()
221
+ {
222
+ @Override
223
+ public void requestOnce(HttpClient client, Response.Listener responseListener)
224
+ {
225
+ Request request = client.newRequest(target).method(method);
226
+ if (headers != null) {
227
+ for (String key : headers.keySet()) {
228
+ request.header(key, headers.get(key));
229
+ }
230
+ }
231
+ request.header(AUTHORIZATION_HEADER, "Bearer " + getAccessToken());
232
+ if (params != null) {
233
+ for (String key : params.keySet()) {
234
+ for (String value : params.get(key)) {
235
+ request.param(key, value);
236
+ }
237
+ }
238
+ }
239
+ LOGGER.info("CALLING {} -> {} - params: {}", method, target, params);
240
+ if (contentProvider != null) {
241
+ request.content(contentProvider);
242
+ }
243
+ request.send(responseListener);
244
+ }
245
+
246
+ @Override
247
+ protected boolean isResponseStatusToRetry(Response response)
248
+ {
249
+ //413 failed job
250
+ //414 failed job
251
+ //502 retry
252
+ return response.getStatus() / 4 != 100;
253
+ }
254
+
255
+ @Override
256
+ protected boolean isExceptionToRetry(Exception exception)
257
+ {
258
+ if (exception instanceof EOFException || exception instanceof TimeoutException || exception instanceof SocketTimeoutException || super.isExceptionToRetry(exception)) {
259
+ return true;
260
+ }
261
+ if (exception instanceof ExecutionException || (exception instanceof IOException && exception.getCause() != null)) {
262
+ return this.toRetry((Exception) exception.getCause());
263
+ }
264
+ if (exception instanceof MarketoAPIException) {
265
+ //Retry Authenticate Exception
266
+ MarketoError error = ((MarketoAPIException) exception).getMarketoErrors().get(0);
267
+ String code = error.getCode();
268
+ switch (code) {
269
+ case "602":
270
+ case "601":
271
+ LOGGER.info("Access token expired");
272
+ renewAccessToken();
273
+ return true;
274
+ case "606":
275
+ try {
276
+ Thread.sleep(marketoLimitIntervalMillis);
277
+ }
278
+ catch (InterruptedException e) {
279
+ LOGGER.error("Encounter exception when waiting for interval limit", e);
280
+ throw new DataException("Exception when wait for interval limit");
281
+ }
282
+ return true;
283
+ case "604":
284
+ case "608":
285
+ case "611":
286
+ case "615":
287
+ case "713":
288
+ case "1029":
289
+ return true;
290
+ default:
291
+ return false;
292
+ }
293
+ }
294
+ return false;
295
+ }
296
+ });
297
+ }
298
+
299
+ @Override
300
+ public void close()
301
+ {
302
+ if (retryHelper != null) {
303
+ retryHelper.close();
304
+ }
305
+ }
306
+ }