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,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
+ }