embulk-output-kintone 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }