embulk-input-marketo-extended 0.6.18

Sign up to get free protection for your applications and to get access to all the features.
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,64 @@
1
+ package org.embulk.input.marketo.delegate;
2
+
3
+ import com.google.common.collect.FluentIterable;
4
+
5
+ import org.embulk.base.restclient.ServiceResponseMapper;
6
+ import org.embulk.base.restclient.record.ServiceRecord;
7
+ import org.embulk.base.restclient.record.ValueLocator;
8
+ import org.embulk.input.marketo.MarketoService;
9
+ import org.embulk.input.marketo.MarketoServiceImpl;
10
+ import org.embulk.input.marketo.MarketoUtils;
11
+ import org.embulk.input.marketo.model.MarketoField;
12
+ import org.embulk.input.marketo.rest.MarketoRestClient;
13
+
14
+ import java.util.Iterator;
15
+ import java.util.List;
16
+
17
+ /**
18
+ * Created by tai.khuu on 9/18/17.
19
+ */
20
+ public class LeadWithListInputPlugin extends MarketoBaseInputPluginDelegate<LeadWithListInputPlugin.PluginTask>
21
+ {
22
+ public interface PluginTask extends MarketoBaseInputPluginDelegate.PluginTask, LeadServiceResponseMapperBuilder.PluginTask
23
+ {
24
+ }
25
+
26
+ public LeadWithListInputPlugin()
27
+ {
28
+ }
29
+
30
+ @Override
31
+ protected Iterator<ServiceRecord> getServiceRecords(MarketoService marketoService, PluginTask task)
32
+ {
33
+ List<String> extractedFields = task.getExtractedFields();
34
+ // Remove LIST_ID_COLUMN_NAME when sent fields to Marketo since LIST_ID_COLUMN_NAME are added by plugin code
35
+ extractedFields.remove(MarketoUtils.LIST_ID_COLUMN_NAME);
36
+ return FluentIterable.from(marketoService.getAllListLead(extractedFields)).transform(MarketoUtils.TRANSFORM_OBJECT_TO_JACKSON_SERVICE_RECORD_FUNCTION).iterator();
37
+ }
38
+
39
+ @Override
40
+ public ServiceResponseMapper<? extends ValueLocator> buildServiceResponseMapper(PluginTask task)
41
+ {
42
+ try (MarketoRestClient marketoRestClient = createMarketoRestClient(task)) {
43
+ MarketoService marketoService = new MarketoServiceImpl(marketoRestClient);
44
+ LeadWithListServiceResponseMapper serviceResponseMapper = new LeadWithListServiceResponseMapper(task, marketoService);
45
+ return serviceResponseMapper.buildServiceResponseMapper(task);
46
+ }
47
+ }
48
+
49
+ private static class LeadWithListServiceResponseMapper extends LeadServiceResponseMapperBuilder<PluginTask>
50
+ {
51
+ public LeadWithListServiceResponseMapper(LeadWithListInputPlugin.PluginTask task, MarketoService marketoService)
52
+ {
53
+ super(task, marketoService);
54
+ }
55
+
56
+ @Override
57
+ protected List<MarketoField> getLeadColumns()
58
+ {
59
+ List<MarketoField> leadColumns = super.getLeadColumns();
60
+ leadColumns.add(new MarketoField(MarketoUtils.LIST_ID_COLUMN_NAME, MarketoField.MarketoDataType.STRING));
61
+ return leadColumns;
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,60 @@
1
+ package org.embulk.input.marketo.delegate;
2
+
3
+ import com.google.common.collect.FluentIterable;
4
+ import org.embulk.base.restclient.ServiceResponseMapper;
5
+ import org.embulk.base.restclient.record.ServiceRecord;
6
+ import org.embulk.base.restclient.record.ValueLocator;
7
+ import org.embulk.input.marketo.MarketoService;
8
+ import org.embulk.input.marketo.MarketoServiceImpl;
9
+ import org.embulk.input.marketo.MarketoUtils;
10
+ import org.embulk.input.marketo.model.MarketoField;
11
+ import org.embulk.input.marketo.rest.MarketoRestClient;
12
+
13
+ import java.util.Iterator;
14
+ import java.util.List;
15
+
16
+ /**
17
+ * Created by tai.khuu on 9/18/17.
18
+ */
19
+ public class LeadWithProgramInputPlugin extends MarketoBaseInputPluginDelegate<LeadWithProgramInputPlugin.PluginTask>
20
+ {
21
+ public interface PluginTask extends MarketoBaseInputPluginDelegate.PluginTask, LeadServiceResponseMapperBuilder.PluginTask
22
+ {
23
+ }
24
+
25
+ @Override
26
+ protected Iterator<ServiceRecord> getServiceRecords(MarketoService marketoService, PluginTask task)
27
+ {
28
+ List<String> fieldNames = task.getExtractedFields();
29
+ // Remove PROGRAM_ID_COLUMN_NAME when sent fields to Marketo since PROGRAM_ID_COLUMN_NAME are added by plugin code
30
+ fieldNames.remove(MarketoUtils.PROGRAM_ID_COLUMN_NAME);
31
+ return FluentIterable.from(marketoService.getAllProgramLead(fieldNames)).
32
+ transform(MarketoUtils.TRANSFORM_OBJECT_TO_JACKSON_SERVICE_RECORD_FUNCTION).iterator();
33
+ }
34
+
35
+ @Override
36
+ public ServiceResponseMapper<? extends ValueLocator> buildServiceResponseMapper(PluginTask task)
37
+ {
38
+ try (MarketoRestClient marketoRestClient = createMarketoRestClient(task)) {
39
+ MarketoService marketoService = new MarketoServiceImpl(marketoRestClient);
40
+ LeadWithProgramServiceResponseMapper serviceResponseMapper = new LeadWithProgramServiceResponseMapper(task, marketoService);
41
+ return serviceResponseMapper.buildServiceResponseMapper(task);
42
+ }
43
+ }
44
+
45
+ private static class LeadWithProgramServiceResponseMapper extends LeadServiceResponseMapperBuilder<PluginTask>
46
+ {
47
+ public LeadWithProgramServiceResponseMapper(LeadWithProgramInputPlugin.PluginTask task, MarketoService marketoService)
48
+ {
49
+ super(task, marketoService);
50
+ }
51
+
52
+ @Override
53
+ protected List<MarketoField> getLeadColumns()
54
+ {
55
+ List<MarketoField> leadColumns = super.getLeadColumns();
56
+ leadColumns.add(new MarketoField(MarketoUtils.PROGRAM_ID_COLUMN_NAME, MarketoField.MarketoDataType.STRING));
57
+ return leadColumns;
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,441 @@
1
+ package org.embulk.input.marketo.delegate;
2
+
3
+ import com.fasterxml.jackson.databind.node.ObjectNode;
4
+ import com.google.common.base.Function;
5
+ import com.google.common.base.Optional;
6
+ import com.google.common.collect.Iterators;
7
+ import org.embulk.base.restclient.jackson.JacksonServiceRecord;
8
+ import org.embulk.base.restclient.jackson.JacksonServiceValue;
9
+ import org.embulk.base.restclient.record.RecordImporter;
10
+ import org.embulk.base.restclient.record.ServiceRecord;
11
+ import org.embulk.base.restclient.record.ValueLocator;
12
+ import org.embulk.config.Config;
13
+ import org.embulk.config.ConfigDefault;
14
+ import org.embulk.config.ConfigDiff;
15
+ import org.embulk.config.ConfigException;
16
+ import org.embulk.config.ConfigInject;
17
+ import org.embulk.config.TaskReport;
18
+ import org.embulk.input.marketo.CsvTokenizer;
19
+ import org.embulk.input.marketo.MarketoService;
20
+ import org.embulk.input.marketo.MarketoServiceImpl;
21
+ import org.embulk.input.marketo.MarketoUtils;
22
+ import org.embulk.input.marketo.rest.MarketoRestClient;
23
+ import org.embulk.spi.BufferAllocator;
24
+ import org.embulk.spi.Column;
25
+ import org.embulk.spi.ColumnVisitor;
26
+ import org.embulk.spi.DataException;
27
+ import org.embulk.spi.Exec;
28
+ import org.embulk.spi.PageBuilder;
29
+ import org.embulk.spi.Schema;
30
+ import org.embulk.spi.json.JsonParser;
31
+ import org.embulk.spi.time.Timestamp;
32
+ import org.embulk.spi.time.TimestampParser;
33
+ import org.embulk.spi.util.InputStreamFileInput;
34
+ import org.embulk.spi.util.LineDecoder;
35
+ import org.joda.time.DateTime;
36
+ import org.msgpack.value.Value;
37
+
38
+ import java.io.InputStream;
39
+ import java.text.DateFormat;
40
+ import java.text.SimpleDateFormat;
41
+ import java.util.ArrayList;
42
+ import java.util.Date;
43
+ import java.util.HashMap;
44
+ import java.util.Iterator;
45
+ import java.util.List;
46
+ import java.util.Map;
47
+ import java.util.NoSuchElementException;
48
+
49
+ /**
50
+ * Created by tai.khuu on 9/18/17.
51
+ */
52
+ public abstract class MarketoBaseBulkExtractInputPlugin<T extends MarketoBaseBulkExtractInputPlugin.PluginTask> extends MarketoBaseInputPluginDelegate<T>
53
+ {
54
+ private static final String FROM_DATE = "from_date";
55
+
56
+ private static final int MARKETO_MAX_RANGE_EXTRACT = 30;
57
+
58
+ public interface PluginTask extends MarketoBaseInputPluginDelegate.PluginTask, CsvTokenizer.PluginTask
59
+ {
60
+ @Config("from_date")
61
+ Date getFromDate();
62
+
63
+ @Config("fetch_days")
64
+ @ConfigDefault("1")
65
+ Integer getFetchDays();
66
+
67
+ @Config("latest_fetch_time")
68
+ @ConfigDefault("null")
69
+ Optional<Long> getLatestFetchTime();
70
+
71
+ @ConfigInject
72
+ BufferAllocator getBufferAllocator();
73
+
74
+ @Config("polling_interval_second")
75
+ @ConfigDefault("60")
76
+ Integer getPollingIntervalSecond();
77
+
78
+ @Config("bulk_job_timeout_second")
79
+ @ConfigDefault("3600")
80
+ Integer getBulkJobTimeoutSecond();
81
+
82
+ @Config("to_date")
83
+ @ConfigDefault("null")
84
+ Optional<Date> getToDate();
85
+
86
+ void setToDate(Optional<Date> toDate);
87
+
88
+ @Config("incremental_column")
89
+ @ConfigDefault("\"createdAt\"")
90
+ //Incremental column are only keep here since we don't want to introduce too much change to plugin
91
+ //Consider remove it in next release
92
+ Optional<String> getIncrementalColumn();
93
+
94
+ void setIncrementalColumn(Optional<String> incrementalColumn);
95
+
96
+ @Config("uid_column")
97
+ @ConfigDefault("null")
98
+ Optional<String> getUidColumn();
99
+ void setUidColumn(Optional<String> uidColumn);
100
+ }
101
+
102
+ @Override
103
+ public void validateInputTask(T task)
104
+ {
105
+ super.validateInputTask(task);
106
+ if (task.getFromDate() == null) {
107
+ throw new ConfigException("From date is required for Bulk Extract");
108
+ }
109
+ if (task.getFromDate().getTime() >= task.getJobStartTime().getMillis()) {
110
+ throw new ConfigException("From date can't not be in future");
111
+ }
112
+ if (task.getIncremental()
113
+ && task.getIncrementalColumn().isPresent()
114
+ && task.getIncrementalColumn().get().equals("updatedAt")) {
115
+ throw new ConfigException("Column 'updatedAt' cannot be incremental imported");
116
+ }
117
+ //Calculate to date
118
+ DateTime toDate = getToDate(task);
119
+ task.setToDate(Optional.of(toDate.toDate()));
120
+ }
121
+
122
+ public DateTime getToDate(T task)
123
+ {
124
+ Date fromDate = task.getFromDate();
125
+ DateTime dateTime = new DateTime(fromDate);
126
+ DateTime toDate = dateTime.plusDays(task.getFetchDays());
127
+ if (toDate.isAfter(task.getJobStartTime())) {
128
+ //Lock down to date
129
+ toDate = task.getJobStartTime();
130
+ }
131
+ return toDate;
132
+ }
133
+
134
+ @Override
135
+ public ConfigDiff buildConfigDiff(T task, Schema schema, int taskCount, List<TaskReport> taskReports)
136
+ {
137
+ ConfigDiff configDiff = super.buildConfigDiff(task, schema, taskCount, taskReports);
138
+ String incrementalColumn = task.getIncrementalColumn().orNull();
139
+ if (incrementalColumn != null && task.getIncremental()) {
140
+ DateFormat df = new SimpleDateFormat(MarketoUtils.MARKETO_DATE_SIMPLE_DATE_FORMAT);
141
+ // We will always move the range forward.
142
+ Date toDate = task.getToDate().orNull();
143
+ configDiff.set(FROM_DATE, df.format(toDate));
144
+ }
145
+ return configDiff;
146
+ }
147
+
148
+ @Override
149
+ public TaskReport ingestServiceData(final T task, RecordImporter recordImporter, int taskIndex, PageBuilder pageBuilder)
150
+ {
151
+ TaskReport taskReport = Exec.newTaskReport();
152
+ if (Exec.isPreview()) {
153
+ return importMockPreviewData(pageBuilder);
154
+ }
155
+ else {
156
+ try (LineDecoderIterator decoderIterator = getLineDecoderIterator(task)) {
157
+ Iterator<Map<String, String>> csvRecords = Iterators.concat(Iterators.transform(decoderIterator, new Function<LineDecoder, Iterator<Map<String, String>>>()
158
+ {
159
+ @Override
160
+ public Iterator<Map<String, String>> apply(LineDecoder input)
161
+ {
162
+ return new CsvRecordIterator(input, task);
163
+ }
164
+ }));
165
+ //Keep the preview code here when we can enable real preview
166
+ if (Exec.isPreview()) {
167
+ csvRecords = Iterators.limit(csvRecords, PREVIEW_RECORD_LIMIT);
168
+ }
169
+ int imported = 0;
170
+ while (csvRecords.hasNext()) {
171
+ Map<String, String> csvRecord = csvRecords.next();
172
+ ObjectNode objectNode = MarketoUtils.OBJECT_MAPPER.valueToTree(csvRecord);
173
+ recordImporter.importRecord(new AllStringJacksonServiceRecord(objectNode), pageBuilder);
174
+ imported = imported + 1;
175
+ }
176
+ return taskReport;
177
+ }
178
+ }
179
+ }
180
+
181
+ /**
182
+ * This method should be removed when we allow skip preview phase
183
+ * @param pageBuilder
184
+ * @return TaskReport
185
+ */
186
+ private TaskReport importMockPreviewData(final PageBuilder pageBuilder)
187
+ {
188
+ final JsonParser jsonParser = new JsonParser();
189
+ Schema schema = pageBuilder.getSchema();
190
+ for (int i = 1; i <= PREVIEW_RECORD_LIMIT; i++) {
191
+ final int rowNum = i;
192
+ schema.visitColumns(new ColumnVisitor()
193
+ {
194
+ @Override
195
+ public void booleanColumn(Column column)
196
+ {
197
+ pageBuilder.setBoolean(column, false);
198
+ }
199
+
200
+ @Override
201
+ public void longColumn(Column column)
202
+ {
203
+ pageBuilder.setLong(column, 12345L);
204
+ }
205
+
206
+ @Override
207
+ public void doubleColumn(Column column)
208
+ {
209
+ pageBuilder.setDouble(column, 12345.123);
210
+ }
211
+
212
+ @Override
213
+ public void stringColumn(Column column)
214
+ {
215
+ pageBuilder.setString(column, column.getName() + "_" + rowNum);
216
+ }
217
+
218
+ @Override
219
+ public void timestampColumn(Column column)
220
+ {
221
+ pageBuilder.setTimestamp(column, Timestamp.ofEpochMilli(System.currentTimeMillis()));
222
+ }
223
+
224
+ @Override
225
+ public void jsonColumn(Column column)
226
+ {
227
+ pageBuilder.setJson(column, jsonParser.parse("{\"mockKey\":\"mockValue\"}"));
228
+ }
229
+ });
230
+ pageBuilder.addRecord();
231
+ }
232
+ return Exec.newTaskReport();
233
+ }
234
+
235
+ private LineDecoderIterator getLineDecoderIterator(T task)
236
+ {
237
+ List<MarketoUtils.DateRange> dateRanges = MarketoUtils.sliceRange(new DateTime(task.getFromDate()), new DateTime(task.getToDate().orNull()), MARKETO_MAX_RANGE_EXTRACT);
238
+ final Iterator<MarketoUtils.DateRange> iterator = dateRanges.iterator();
239
+ return new LineDecoderIterator(iterator, task);
240
+ }
241
+
242
+ @Override
243
+ protected final Iterator<ServiceRecord> getServiceRecords(MarketoService marketoService, T task)
244
+ {
245
+ throw new UnsupportedOperationException();
246
+ }
247
+
248
+ protected abstract InputStream getExtractedStream(MarketoService service, T task, DateTime fromDate, DateTime toDate);
249
+
250
+ private static class AllStringJacksonServiceRecord extends JacksonServiceRecord
251
+ {
252
+ public AllStringJacksonServiceRecord(ObjectNode record)
253
+ {
254
+ super(record);
255
+ }
256
+
257
+ @Override
258
+ public JacksonServiceValue getValue(ValueLocator locator)
259
+ {
260
+ // We know that this thing only contain text.
261
+ JacksonServiceValue value = super.getValue(locator);
262
+ return new StringConverterJacksonServiceRecord(value.stringValue());
263
+ }
264
+ }
265
+
266
+ private static class StringConverterJacksonServiceRecord extends JacksonServiceValue
267
+ {
268
+ private String textValue;
269
+
270
+ public StringConverterJacksonServiceRecord(String textValue)
271
+ {
272
+ super(null);
273
+ this.textValue = textValue;
274
+ }
275
+
276
+ @Override
277
+ public boolean isNull()
278
+ {
279
+ return textValue == null || textValue.equals("null");
280
+ }
281
+
282
+ @Override
283
+ public boolean booleanValue()
284
+ {
285
+ return Boolean.parseBoolean(textValue);
286
+ }
287
+
288
+ @Override
289
+ public double doubleValue()
290
+ {
291
+ return Double.parseDouble(textValue);
292
+ }
293
+
294
+ @Override
295
+ public Value jsonValue(JsonParser jsonParser)
296
+ {
297
+ return jsonParser.parse(textValue);
298
+ }
299
+
300
+ @Override
301
+ public long longValue()
302
+ {
303
+ return Long.parseLong(textValue);
304
+ }
305
+
306
+ @Override
307
+ public String stringValue()
308
+ {
309
+ return textValue;
310
+ }
311
+
312
+ @Override
313
+ public Timestamp timestampValue(TimestampParser timestampParser)
314
+ {
315
+ return timestampParser.parse(textValue);
316
+ }
317
+ }
318
+
319
+ private final class LineDecoderIterator implements Iterator<LineDecoder>, AutoCloseable
320
+ {
321
+ private LineDecoder currentLineDecoder;
322
+
323
+ private Iterator<MarketoUtils.DateRange> dateRangeIterator;
324
+
325
+ private MarketoService marketoService;
326
+
327
+ private MarketoRestClient marketoRestClient;
328
+ private T task;
329
+ public LineDecoderIterator(Iterator<MarketoUtils.DateRange> dateRangeIterator, T task)
330
+ {
331
+ marketoRestClient = createMarketoRestClient(task);
332
+ marketoService = new MarketoServiceImpl(marketoRestClient);
333
+ this.dateRangeIterator = dateRangeIterator;
334
+ this.task = task;
335
+ }
336
+
337
+ @Override
338
+ public void close()
339
+ {
340
+ if (currentLineDecoder != null) {
341
+ currentLineDecoder.close();
342
+ }
343
+ if (marketoRestClient != null) {
344
+ marketoRestClient.close();
345
+ }
346
+ }
347
+
348
+ @Override
349
+ public boolean hasNext()
350
+ {
351
+ return dateRangeIterator.hasNext();
352
+ }
353
+
354
+ @Override
355
+ public LineDecoder next()
356
+ {
357
+ if (hasNext()) {
358
+ MarketoUtils.DateRange next = dateRangeIterator.next();
359
+ InputStream extractedStream = getExtractedStream(marketoService, task, next.fromDate, next.toDate);
360
+ currentLineDecoder = new LineDecoder(new InputStreamFileInput(task.getBufferAllocator(), extractedStream), task);
361
+ return currentLineDecoder;
362
+ }
363
+ throw new NoSuchElementException();
364
+ }
365
+
366
+ @Override
367
+ public void remove()
368
+ {
369
+ throw new UnsupportedOperationException("Removed are not supported");
370
+ }
371
+ }
372
+
373
+ private class CsvRecordIterator implements Iterator<Map<String, String>>
374
+ {
375
+ private CsvTokenizer tokenizer;
376
+
377
+ private List<String> headers;
378
+
379
+ private Map<String, String> currentCsvRecord;
380
+ public CsvRecordIterator(LineDecoder lineDecoder, T task)
381
+ {
382
+ tokenizer = new CsvTokenizer(lineDecoder, task);
383
+ if (!tokenizer.nextFile()) {
384
+ throw new DataException("Can't read extract input stream");
385
+ }
386
+ headers = new ArrayList<>();
387
+ tokenizer.nextRecord();
388
+ while (tokenizer.hasNextColumn()) {
389
+ headers.add(tokenizer.nextColumn());
390
+ }
391
+ }
392
+
393
+ @Override
394
+ public boolean hasNext()
395
+ {
396
+ if (currentCsvRecord == null) {
397
+ currentCsvRecord = getNextCSVRecord();
398
+ }
399
+ return currentCsvRecord != null;
400
+ }
401
+
402
+ @Override
403
+ public Map<String, String> next()
404
+ {
405
+ try {
406
+ if (hasNext()) {
407
+ return currentCsvRecord;
408
+ }
409
+ }
410
+ finally {
411
+ currentCsvRecord = null;
412
+ }
413
+ throw new NoSuchElementException();
414
+ }
415
+
416
+ @Override
417
+ public void remove()
418
+ {
419
+ throw new UnsupportedOperationException();
420
+ }
421
+ private Map<String, String> getNextCSVRecord()
422
+ {
423
+ if (!tokenizer.nextRecord()) {
424
+ return null;
425
+ }
426
+ Map<String, String> kvMap = new HashMap<>();
427
+ try {
428
+ int i = 0;
429
+ while (tokenizer.hasNextColumn()) {
430
+ kvMap.put(headers.get(i), tokenizer.nextColumnOrNull());
431
+ i++;
432
+ }
433
+ }
434
+ catch (CsvTokenizer.InvalidValueException ex) {
435
+ throw new DataException("Encounter exception when parse csv file. Please check to see if you are using the correct" +
436
+ "quote or escape character.", ex);
437
+ }
438
+ return kvMap;
439
+ }
440
+ }
441
+ }