embulk-output-kintone 0.4.0 → 0.4.1

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -0
  3. data/.gitignore +0 -1
  4. data/build.gradle +18 -19
  5. data/classpath/embulk-output-kintone-0.4.1.jar +0 -0
  6. data/classpath/shadow-kintone-java-client-0.4.1-all.jar +0 -0
  7. data/gradle/wrapper/gradle-wrapper.properties +1 -1
  8. data/settings.gradle +2 -0
  9. data/shadow-kintone-java-client/build.gradle +35 -0
  10. data/src/main/java/org/embulk/output/kintone/KintonePageOutput.java +166 -121
  11. data/src/main/java/org/embulk/output/kintone/KintoneRetryOption.java +19 -0
  12. data/src/main/java/org/embulk/output/kintone/PluginTask.java +3 -3
  13. data/src/test/java/com/kintone/client/Json.java +16 -0
  14. data/src/test/java/org/embulk/output/kintone/KintoneColumnOptionBuilder.java +63 -0
  15. data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorTest.java +297 -0
  16. data/src/test/java/org/embulk/output/kintone/KintoneColumnVisitorVerifier.java +52 -0
  17. data/src/test/java/org/embulk/output/kintone/KintonePageOutputVerifier.java +226 -0
  18. data/src/test/java/org/embulk/output/kintone/OutputPageBuilder.java +92 -0
  19. data/src/test/java/org/embulk/output/kintone/TestKintoneOutputPlugin.java +163 -1
  20. data/src/test/java/org/embulk/output/kintone/TestTask.java +40 -0
  21. data/src/test/java/org/embulk/output/kintone/TestTaskMode.java +31 -0
  22. data/src/test/resources/logback-test.xml +14 -0
  23. data/src/test/resources/org/embulk/output/kintone/config.yml +4 -0
  24. data/src/test/resources/org/embulk/output/kintone/task/config.yml +1 -0
  25. data/src/test/resources/org/embulk/output/kintone/task/mode/config.yml +54 -0
  26. data/src/test/resources/org/embulk/output/kintone/task/mode/input.csv +7 -0
  27. data/src/test/resources/org/embulk/output/kintone/task/mode/insert_add_records.jsonl +6 -0
  28. data/src/test/resources/org/embulk/output/kintone/task/mode/update_update_records.jsonl +3 -0
  29. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_add_records.jsonl +2 -0
  30. data/src/test/resources/org/embulk/output/kintone/task/mode/upsert_update_records.jsonl +4 -0
  31. data/src/test/resources/org/embulk/output/kintone/task/mode/values.json +1 -0
  32. metadata +25 -3
  33. data/classpath/embulk-output-kintone-0.4.0.jar +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d405f264473164aaf9581956d1a5343fe993a4a1
4
- data.tar.gz: 85988a65971c21fbc058401a9af1e600b8029f1d
3
+ metadata.gz: c677006a4f3dfdbec29c97e039045874614b3e99
4
+ data.tar.gz: 9c1fff33d958a4ee8be940da64cc7e10af04eb92
5
5
  SHA512:
6
- metadata.gz: bc2eb92ad6fb1a200f4567aeb4e57baebbdf636a94ab40834c4864d48dc83891fa2fc23152e86e283fe28d7fa9248c1bd08497fd7f0ab4887def5ca3c6f5dafb
7
- data.tar.gz: 9a8295b11401e64357a67ffb733e51f45e8321b68377e21e3d66cd50ea3c20f62bbf7c9d28e58d44b9fb805eb483b35af96e72868ecae383fb81d53935c0c6e5
6
+ metadata.gz: d6e53840dad2b56c75e7422a769f0ae2eb8b24ce6034cc269255952e22442c77164c3bdac78a08f28086e5318df2318f99ad924d1bd85af8966ae83e5d57d627
7
+ data.tar.gz: 641e40a2986787204ef8e0feec1b916a2d4d0b5c0cc1d5e9d0137f38eaf8ed43b3b5b0b2f19f3304ee8736668b049d0a115836a62d8d3cd6efa20fe61ecc3be5
@@ -1,6 +1,7 @@
1
1
  name: main
2
2
 
3
3
  on:
4
+ workflow_dispatch:
4
5
  push:
5
6
  branches:
6
7
  - "master"
data/.gitignore CHANGED
@@ -10,4 +10,3 @@ build/
10
10
  /.metadata/
11
11
  .classpath
12
12
  .project
13
- config.yml
data/build.gradle CHANGED
@@ -1,7 +1,7 @@
1
1
  plugins {
2
2
  id "com.jfrog.bintray" version "1.1"
3
3
  id "com.github.jruby-gradle.base" version "1.5.0"
4
- id "com.github.johnrengelman.shadow" version "4.0.3"
4
+ id "com.github.johnrengelman.shadow" version "6.1.0" apply false
5
5
  id "java"
6
6
  id "checkstyle"
7
7
  id "com.palantir.git-version" version "0.12.3"
@@ -12,9 +12,6 @@ repositories {
12
12
  mavenCentral()
13
13
  jcenter()
14
14
  }
15
- configurations {
16
- provided
17
- }
18
15
 
19
16
  version = {
20
17
  def vd = versionDetails()
@@ -29,26 +26,23 @@ version = {
29
26
  sourceCompatibility = 1.8
30
27
  targetCompatibility = 1.8
31
28
 
32
- shadowJar {
33
- exclude "org/embulk/plugin/**"
34
- relocate "com.fasterxml.jackson", "embulk.kintone.com.fasterxml.jackson"
35
- }
36
-
37
29
  dependencies {
38
- compile "org.embulk:embulk-core:0.9.20"
39
- provided "org.embulk:embulk-core:0.9.20"
40
- compile "com.kintone:kintone-java-client:1.0.2"
30
+ compileOnly "org.embulk:embulk-core:0.9.23"
31
+ implementation project(path: ":shadow-kintone-java-client", configuration: "shadow")
41
32
 
42
- // compile "YOUR_JAR_DEPENDENCY_GROUP:YOUR_JAR_DEPENDENCY_MODULE:YOUR_JAR_DEPENDENCY_VERSION"
43
- testCompile "junit:junit:4.+"
33
+ testImplementation "junit:junit:4.+"
34
+ testImplementation "org.embulk:embulk-test:0.9.23"
35
+ testImplementation "org.embulk:embulk-standards:0.9.23"
36
+ testImplementation "org.embulk:embulk-deps-buffer:0.9.23"
37
+ testImplementation "org.embulk:embulk-deps-config:0.9.23"
38
+ testImplementation "org.mockito:mockito-inline:4.11.0"
39
+ testImplementation "ch.qos.logback:logback-classic:1.3.8"
40
+ testImplementation "net.jcip:jcip-annotations:1.0"
44
41
  }
45
42
 
46
- task classpath(type: Copy, dependsOn: ["jar", "shadowJar"]) {
43
+ task classpath(type: Copy, dependsOn: ["jar"]) {
47
44
  doFirst { file("classpath").deleteDir() }
48
- from (configurations.runtime - configurations.provided
49
- + configurations.shadow
50
- - files(shadowJar.getIncludedDependencies())
51
- + files(shadowJar.archivePath))
45
+ from (configurations.runtimeClasspath + files(jar.archivePath))
52
46
  into "classpath"
53
47
  }
54
48
  clean { delete "classpath" }
@@ -127,3 +121,8 @@ spotless {
127
121
  toggleOffOn()
128
122
  }
129
123
  }
124
+
125
+ test {
126
+ forkEvery = 1
127
+ maxHeapSize = "1g"
128
+ }
@@ -1,5 +1,5 @@
1
1
  distributionBase=GRADLE_USER_HOME
2
2
  distributionPath=wrapper/dists
3
- distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
3
+ distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip
4
4
  zipStoreBase=GRADLE_USER_HOME
5
5
  zipStorePath=wrapper/dists
data/settings.gradle ADDED
@@ -0,0 +1,2 @@
1
+ rootProject.name = "embulk-output-kintone"
2
+ include "shadow-kintone-java-client"
@@ -0,0 +1,35 @@
1
+ plugins {
2
+ id "java"
3
+ id "maven-publish"
4
+ id "com.github.johnrengelman.shadow"
5
+ }
6
+
7
+ repositories {
8
+ mavenCentral()
9
+ }
10
+
11
+ group = "${rootProject.group}"
12
+ version = "${rootProject.version}"
13
+
14
+ sourceCompatibility = 1.8
15
+ targetCompatibility = 1.8
16
+
17
+ configurations {
18
+ runtimeClasspath {
19
+ resolutionStrategy.activateDependencyLocking()
20
+ }
21
+ shadow {
22
+ resolutionStrategy.activateDependencyLocking()
23
+ transitive = false
24
+ }
25
+ }
26
+
27
+ dependencies {
28
+ implementation("com.kintone:kintone-java-client:1.4.0") {
29
+ exclude group: "org.slf4j", module: "slf4j-api"
30
+ }
31
+ }
32
+
33
+ shadowJar {
34
+ relocate "com.fasterxml.jackson", "embulk.kintone.com.fasterxml.jackson"
35
+ }
@@ -1,18 +1,23 @@
1
1
  package org.embulk.output.kintone;
2
2
 
3
+ import static org.embulk.spi.util.RetryExecutor.retryExecutor;
4
+
5
+ import com.fasterxml.jackson.databind.JsonNode;
6
+ import com.fasterxml.jackson.databind.ObjectMapper;
3
7
  import com.kintone.client.KintoneClient;
4
8
  import com.kintone.client.KintoneClientBuilder;
5
9
  import com.kintone.client.api.record.GetRecordsByCursorResponseBody;
10
+ import com.kintone.client.exception.KintoneApiRuntimeException;
6
11
  import com.kintone.client.model.record.FieldType;
7
12
  import com.kintone.client.model.record.Record;
8
13
  import com.kintone.client.model.record.RecordForUpdate;
9
14
  import com.kintone.client.model.record.UpdateKey;
15
+ import java.io.IOException;
10
16
  import java.math.BigDecimal;
11
17
  import java.util.ArrayList;
12
18
  import java.util.Arrays;
13
19
  import java.util.Collections;
14
20
  import java.util.List;
15
- import java.util.concurrent.TimeUnit;
16
21
  import java.util.stream.Collectors;
17
22
  import org.embulk.config.ConfigException;
18
23
  import org.embulk.config.TaskReport;
@@ -22,6 +27,8 @@ import org.embulk.spi.Page;
22
27
  import org.embulk.spi.PageReader;
23
28
  import org.embulk.spi.Schema;
24
29
  import org.embulk.spi.TransactionalPageOutput;
30
+ import org.embulk.spi.util.RetryExecutor.RetryGiveupException;
31
+ import org.embulk.spi.util.RetryExecutor.Retryable;
25
32
  import org.slf4j.Logger;
26
33
  import org.slf4j.LoggerFactory;
27
34
 
@@ -29,6 +36,12 @@ public class KintonePageOutput implements TransactionalPageOutput {
29
36
  public static final int UPSERT_BATCH_SIZE = 10000;
30
37
  public static final int CHUNK_SIZE = 100;
31
38
  private static final Logger LOGGER = LoggerFactory.getLogger(KintonePageOutput.class);
39
+ private static final List<String> RETRYABLE_ERROR_CODES =
40
+ Arrays.asList(
41
+ "GAIA_TM12", // 作成できるカーソルの上限に達しているため、カーソ ルを作成できません。不要なカーソルを削除するか、しばらく経ってから再実行してください。
42
+ "GAIA_RE18", // データベースのロックに失敗したため、変更を保存できませんでした。時間をおいて再度お試しください。
43
+ "GAIA_DA02" // データベースのロックに失敗したため、変更を保存できませんでした。時間をおいて再度お試しください。
44
+ );
32
45
  private final PageReader pageReader;
33
46
  private final PluginTask task;
34
47
  private KintoneClient client;
@@ -104,133 +117,176 @@ public class KintonePageOutput implements TransactionalPageOutput {
104
117
  }
105
118
  }
106
119
 
120
+ private void update(ArrayList<RecordForUpdate> records) {
121
+ execute(
122
+ client -> {
123
+ client.record().updateRecords(task.getAppId(), records);
124
+ });
125
+ }
126
+
127
+ private void insert(ArrayList<Record> records) {
128
+ execute(
129
+ client -> {
130
+ client.record().addRecords(task.getAppId(), records);
131
+ });
132
+ }
133
+
107
134
  private void execute(Consumer<KintoneClient> operation) {
108
135
  connect(task);
109
- if (this.client != null) {
110
- operation.accept(this.client);
111
- } else {
136
+ if (this.client == null) {
112
137
  throw new RuntimeException("Failed to connect to kintone.");
113
138
  }
139
+ KintoneRetryOption retryOption = task.getRetryOptions();
140
+ try {
141
+ retryExecutor()
142
+ .withRetryLimit(retryOption.getLimit())
143
+ .withInitialRetryWait(retryOption.getInitialWaitMillis())
144
+ .withMaxRetryWait(retryOption.getMaxWaitMillis())
145
+ .runInterruptible(
146
+ new Retryable<Void>() {
147
+
148
+ @Override
149
+ public Void call() throws Exception {
150
+ operation.accept(client);
151
+ return null;
152
+ }
153
+
154
+ @Override
155
+ public boolean isRetryableException(Exception e) {
156
+ if (!(e instanceof KintoneApiRuntimeException)) {
157
+ return false;
158
+ }
159
+
160
+ try {
161
+ ObjectMapper mapper = new ObjectMapper();
162
+ JsonNode content =
163
+ mapper.readTree(((KintoneApiRuntimeException) e).getContent());
164
+ String code = content.get("code").textValue();
165
+ return RETRYABLE_ERROR_CODES.contains(code);
166
+ } catch (IOException ex) {
167
+ throw new RuntimeException(ex);
168
+ }
169
+ }
170
+
171
+ @Override
172
+ public void onRetry(
173
+ Exception exception, int retryCount, int retryLimit, int retryWait)
174
+ throws RetryGiveupException {
175
+ String message =
176
+ String.format(
177
+ "Retrying %d/%d after %d seconds. Message: %s",
178
+ retryCount, retryLimit, retryWait / 1000, exception.getMessage());
179
+ if (retryCount % 3 == 0) {
180
+ LOGGER.warn(message, exception);
181
+ } else {
182
+ LOGGER.warn(message);
183
+ }
184
+ }
185
+
186
+ @Override
187
+ public void onGiveup(Exception firstException, Exception lastException)
188
+ throws RetryGiveupException {}
189
+ });
190
+ } catch (RetryGiveupException | InterruptedException e) {
191
+ throw new RuntimeException("kintone throw exception", e);
192
+ }
114
193
  }
115
194
 
116
195
  private void insertPage(final Page page) {
117
- execute(
118
- client -> {
119
- try {
120
- ArrayList<Record> records = new ArrayList<>();
121
- pageReader.setPage(page);
122
- KintoneColumnVisitor visitor =
123
- new KintoneColumnVisitor(pageReader, task.getColumnOptions());
124
- while (pageReader.nextRecord()) {
125
- Record record = new Record();
126
- visitor.setRecord(record);
127
- for (Column column : pageReader.getSchema().getColumns()) {
128
- column.visit(visitor);
129
- }
130
-
131
- records.add(record);
132
- if (records.size() == CHUNK_SIZE) {
133
- client.record().addRecords(task.getAppId(), records);
134
- records.clear();
135
- sleep();
136
- }
137
- }
138
- if (records.size() > 0) {
139
- client.record().addRecords(task.getAppId(), records);
140
- }
141
- } catch (Exception e) {
142
- throw new RuntimeException("kintone throw exception", e);
143
- }
144
- });
196
+
197
+ ArrayList<Record> records = new ArrayList<>();
198
+ pageReader.setPage(page);
199
+ KintoneColumnVisitor visitor = new KintoneColumnVisitor(pageReader, task.getColumnOptions());
200
+ while (pageReader.nextRecord()) {
201
+ Record record = new Record();
202
+ visitor.setRecord(record);
203
+ for (Column column : pageReader.getSchema().getColumns()) {
204
+ column.visit(visitor);
205
+ }
206
+
207
+ records.add(record);
208
+ if (records.size() == CHUNK_SIZE) {
209
+ insert(records);
210
+ records.clear();
211
+ }
212
+ }
213
+ if (records.size() > 0) {
214
+ insert(records);
215
+ }
145
216
  }
146
217
 
147
218
  private void updatePage(final Page page) {
148
- execute(
149
- client -> {
150
- try {
151
- ArrayList<RecordForUpdate> updateRecords = new ArrayList<>();
152
- pageReader.setPage(page);
153
-
154
- KintoneColumnVisitor visitor =
155
- new KintoneColumnVisitor(
156
- pageReader,
157
- task.getColumnOptions(),
158
- task.getUpdateKeyName()
159
- .orElseThrow(
160
- () -> new RuntimeException("unreachable"))); // Already validated
161
- while (pageReader.nextRecord()) {
162
- Record record = new Record();
163
- UpdateKey updateKey = new UpdateKey();
164
- visitor.setRecord(record);
165
- visitor.setUpdateKey(updateKey);
166
- for (Column column : pageReader.getSchema().getColumns()) {
167
- column.visit(visitor);
168
- }
169
-
170
- if (updateKey.getValue() == "") {
171
- continue;
172
- }
173
-
174
- record.removeField(updateKey.getField());
175
- updateRecords.add(new RecordForUpdate(updateKey, record));
176
- if (updateRecords.size() == CHUNK_SIZE) {
177
- client.record().updateRecords(task.getAppId(), updateRecords);
178
- updateRecords.clear();
179
- sleep();
180
- }
181
- }
182
- if (updateRecords.size() > 0) {
183
- client.record().updateRecords(task.getAppId(), updateRecords);
184
- }
185
- } catch (Exception e) {
186
- throw new RuntimeException("kintone throw exception", e);
187
- }
188
- });
219
+ ArrayList<RecordForUpdate> updateRecords = new ArrayList<>();
220
+ pageReader.setPage(page);
221
+
222
+ KintoneColumnVisitor visitor =
223
+ new KintoneColumnVisitor(
224
+ pageReader,
225
+ task.getColumnOptions(),
226
+ task.getUpdateKeyName()
227
+ .orElseThrow(() -> new RuntimeException("unreachable"))); // Already validated
228
+ while (pageReader.nextRecord()) {
229
+ Record record = new Record();
230
+ UpdateKey updateKey = new UpdateKey();
231
+ visitor.setRecord(record);
232
+ visitor.setUpdateKey(updateKey);
233
+ for (Column column : pageReader.getSchema().getColumns()) {
234
+ column.visit(visitor);
235
+ }
236
+
237
+ if (updateKey.getValue() == "") {
238
+ continue;
239
+ }
240
+
241
+ record.removeField(updateKey.getField());
242
+ updateRecords.add(new RecordForUpdate(updateKey, record));
243
+ if (updateRecords.size() == CHUNK_SIZE) {
244
+ update(updateRecords);
245
+ updateRecords.clear();
246
+ }
247
+ }
248
+ if (updateRecords.size() > 0) {
249
+ update(updateRecords);
250
+ }
189
251
  }
190
252
 
191
253
  private void upsertPage(final Page page) {
192
254
  execute(
193
255
  client -> {
194
- try {
195
- ArrayList<Record> records = new ArrayList<>();
196
- ArrayList<UpdateKey> updateKeys = new ArrayList<>();
197
- pageReader.setPage(page);
198
-
199
- KintoneColumnVisitor visitor =
200
- new KintoneColumnVisitor(
201
- pageReader,
202
- task.getColumnOptions(),
203
- task.getUpdateKeyName()
204
- .orElseThrow(
205
- () -> new RuntimeException("unreachable"))); // Already validated
206
- while (pageReader.nextRecord()) {
207
- Record record = new Record();
208
- UpdateKey updateKey = new UpdateKey();
209
- visitor.setRecord(record);
210
- visitor.setUpdateKey(updateKey);
211
- for (Column column : pageReader.getSchema().getColumns()) {
212
- column.visit(visitor);
213
- }
214
- records.add(record);
215
- updateKeys.add(updateKey);
216
-
217
- if (records.size() == UPSERT_BATCH_SIZE) {
218
- upsert(records, updateKeys);
219
- records.clear();
220
- updateKeys.clear();
221
- }
256
+ ArrayList<Record> records = new ArrayList<>();
257
+ ArrayList<UpdateKey> updateKeys = new ArrayList<>();
258
+ pageReader.setPage(page);
259
+
260
+ KintoneColumnVisitor visitor =
261
+ new KintoneColumnVisitor(
262
+ pageReader,
263
+ task.getColumnOptions(),
264
+ task.getUpdateKeyName()
265
+ .orElseThrow(() -> new RuntimeException("unreachable"))); // Already validated
266
+ while (pageReader.nextRecord()) {
267
+ Record record = new Record();
268
+ UpdateKey updateKey = new UpdateKey();
269
+ visitor.setRecord(record);
270
+ visitor.setUpdateKey(updateKey);
271
+ for (Column column : pageReader.getSchema().getColumns()) {
272
+ column.visit(visitor);
222
273
  }
223
- if (records.size() > 0) {
274
+ records.add(record);
275
+ updateKeys.add(updateKey);
276
+
277
+ if (records.size() == UPSERT_BATCH_SIZE) {
224
278
  upsert(records, updateKeys);
279
+ records.clear();
280
+ updateKeys.clear();
225
281
  }
226
- } catch (Exception e) {
227
- throw new RuntimeException("kintone throw exception", e);
282
+ }
283
+ if (records.size() > 0) {
284
+ upsert(records, updateKeys);
228
285
  }
229
286
  });
230
287
  }
231
288
 
232
- private void upsert(ArrayList<Record> records, ArrayList<UpdateKey> updateKeys)
233
- throws InterruptedException {
289
+ private void upsert(ArrayList<Record> records, ArrayList<UpdateKey> updateKeys) {
234
290
  if (records.size() != updateKeys.size()) {
235
291
  throw new RuntimeException("records.size() != updateKeys.size()");
236
292
  }
@@ -274,20 +330,18 @@ public class KintonePageOutput implements TransactionalPageOutput {
274
330
  }
275
331
 
276
332
  if (insertRecords.size() == CHUNK_SIZE) {
277
- client.record().addRecords(task.getAppId(), insertRecords);
333
+ insert(insertRecords);
278
334
  insertRecords.clear();
279
- sleep();
280
335
  } else if (updateRecords.size() == CHUNK_SIZE) {
281
- client.record().updateRecords(task.getAppId(), updateRecords);
336
+ update(updateRecords);
282
337
  updateRecords.clear();
283
- sleep();
284
338
  }
285
339
  }
286
340
  if (insertRecords.size() > 0) {
287
- client.record().addRecords(task.getAppId(), insertRecords);
341
+ insert(insertRecords);
288
342
  }
289
343
  if (updateRecords.size() > 0) {
290
- client.record().updateRecords(task.getAppId(), updateRecords);
344
+ update(updateRecords);
291
345
  }
292
346
  }
293
347
 
@@ -325,13 +379,4 @@ public class KintonePageOutput implements TransactionalPageOutput {
325
379
  private boolean existsRecord(List<String> distValues, UpdateKey updateKey) {
326
380
  return distValues.stream().anyMatch(v -> v.equals(updateKey.getValue().toString()));
327
381
  }
328
-
329
- private void sleep() throws InterruptedException {
330
- if (!task.getIntervalSeconds().isPresent()) {
331
- return;
332
- }
333
- Integer interval = task.getIntervalSeconds().get();
334
- LOGGER.info(String.format("sleep %d seconds.", interval));
335
- TimeUnit.SECONDS.sleep(interval);
336
- }
337
382
  }
@@ -0,0 +1,19 @@
1
+ package org.embulk.output.kintone;
2
+
3
+ import org.embulk.config.Config;
4
+ import org.embulk.config.ConfigDefault;
5
+ import org.embulk.config.Task;
6
+
7
+ public interface KintoneRetryOption extends Task {
8
+ @Config("limit")
9
+ @ConfigDefault("10")
10
+ Integer getLimit();
11
+
12
+ @Config("initial_wait_millis")
13
+ @ConfigDefault("1000")
14
+ Integer getInitialWaitMillis();
15
+
16
+ @Config("max_wait_millis")
17
+ @ConfigDefault("60000")
18
+ Integer getMaxWaitMillis();
19
+ }
@@ -49,7 +49,7 @@ public interface PluginTask extends Task {
49
49
  @ConfigDefault("null")
50
50
  Optional<String> getUpdateKeyName();
51
51
 
52
- @Config("interval_seconds")
53
- @ConfigDefault("null")
54
- Optional<Integer> getIntervalSeconds();
52
+ @Config("retry_options")
53
+ @ConfigDefault("{}")
54
+ KintoneRetryOption getRetryOptions();
55
55
  }
@@ -0,0 +1,16 @@
1
+ package com.kintone.client;
2
+
3
+ import java.io.ByteArrayInputStream;
4
+ import java.nio.charset.StandardCharsets;
5
+
6
+ public class Json {
7
+ private static final JsonMapper MAPPER = new JsonMapper();
8
+
9
+ public static String format(Object o) {
10
+ return new String(MAPPER.format(o), StandardCharsets.UTF_8);
11
+ }
12
+
13
+ public static <T> T parse(String s, Class<T> clazz) {
14
+ return MAPPER.parse(new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)), clazz);
15
+ }
16
+ }
@@ -0,0 +1,63 @@
1
+ package org.embulk.output.kintone;
2
+
3
+ import java.util.Optional;
4
+ import org.embulk.config.TaskSource;
5
+
6
+ public class KintoneColumnOptionBuilder {
7
+ private String type;
8
+ private String fieldCode;
9
+ private String timezone;
10
+ private String valueSeparator;
11
+
12
+ public KintoneColumnOptionBuilder setType(String type) {
13
+ this.type = type;
14
+ return this;
15
+ }
16
+
17
+ public KintoneColumnOptionBuilder setFieldCode(String fieldCode) {
18
+ this.fieldCode = fieldCode;
19
+ return this;
20
+ }
21
+
22
+ public KintoneColumnOptionBuilder setTimezone(String timezone) {
23
+ this.timezone = timezone;
24
+ return this;
25
+ }
26
+
27
+ public KintoneColumnOptionBuilder setValueSeparator(String valueSeparator) {
28
+ this.valueSeparator = valueSeparator;
29
+ return this;
30
+ }
31
+
32
+ public KintoneColumnOption build() {
33
+ return new KintoneColumnOption() {
34
+ @Override
35
+ public String getType() {
36
+ return type;
37
+ }
38
+
39
+ @Override
40
+ public String getFieldCode() {
41
+ return fieldCode;
42
+ }
43
+
44
+ @Override
45
+ public Optional<String> getTimezone() {
46
+ return Optional.ofNullable(timezone);
47
+ }
48
+
49
+ @Override
50
+ public String getValueSeparator() {
51
+ return valueSeparator;
52
+ }
53
+
54
+ @Override
55
+ public void validate() {}
56
+
57
+ @Override
58
+ public TaskSource dump() {
59
+ return null;
60
+ }
61
+ };
62
+ }
63
+ }